az2aws 1.1.3 → 1.3.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.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +29 -0
- package/README.md +43 -41
- package/issue/issues.md +441 -1
- package/lib/configureProfileAsync.js +1 -1
- package/lib/index.js +7 -3
- package/lib/login.js +43 -338
- package/lib/loginStates.js +332 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.0](https://github.com/kuma0128/az2aws/compare/v1.2.0...v1.3.0) (2026-01-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Add Comprehensive Loginstate Tests and Implementation ([#110](https://github.com/kuma0128/az2aws/issues/110)) ([09fce50](https://github.com/kuma0128/az2aws/commit/09fce501050731e2b0e5063ef8d2d5e4076827a1))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* Apply Prettier formatting and add region logging to login functions ([#109](https://github.com/kuma0128/az2aws/issues/109)) ([26a5ef6](https://github.com/kuma0128/az2aws/commit/26a5ef636014f56ad77813f42e866a25b08be2f3))
|
|
14
|
+
* clarify session duration validation message ([#91](https://github.com/kuma0128/az2aws/issues/91)) ([22d87ec](https://github.com/kuma0128/az2aws/commit/22d87ec57318c6dc69d09e098d7e123d07df882e))
|
|
15
|
+
* correct typo 'occured' to 'occurred' in error message ([#86](https://github.com/kuma0128/az2aws/issues/86)) ([b0a75d2](https://github.com/kuma0128/az2aws/commit/b0a75d2c7cecaef7888d17a9880bcd63000713b8))
|
|
16
|
+
* enforce defaults for no-prompt role selection ([#90](https://github.com/kuma0128/az2aws/issues/90)) ([bea40f6](https://github.com/kuma0128/az2aws/commit/bea40f64a9dc6851b34a396fdd315752669c1d9d))
|
|
17
|
+
|
|
18
|
+
## [1.2.0](https://github.com/kuma0128/az2aws/compare/v1.1.3...v1.2.0) (2026-01-22)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
* Add version flag to CLI command ([#67](https://github.com/kuma0128/az2aws/issues/67)) ([b89290f](https://github.com/kuma0128/az2aws/commit/b89290fe16d554f6a8a1bf09df0194a64d692b55))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Bug Fixes
|
|
27
|
+
|
|
28
|
+
* Add default duration of 1 hour if parsing fails ([#70](https://github.com/kuma0128/az2aws/issues/70)) ([337d12c](https://github.com/kuma0128/az2aws/commit/337d12c90ab0eccf4034bd438ecfb2f0ad98db47))
|
|
29
|
+
* Fix SAML assertion decoding to use UTF-8 encoding ([#72](https://github.com/kuma0128/az2aws/issues/72)) ([14e44a7](https://github.com/kuma0128/az2aws/commit/14e44a7ffe19e48177078aa6d87feb7e8ecf0c94))
|
|
30
|
+
* resolve --no-verify-ssl and proxy settings conflict ([#73](https://github.com/kuma0128/az2aws/issues/73)) ([3fd9adf](https://github.com/kuma0128/az2aws/commit/3fd9adf6dd39109bb428b56215200ad1df3752a9))
|
|
31
|
+
|
|
3
32
|
## [1.1.3](https://github.com/kuma0128/az2aws/compare/v1.1.2...v1.1.3) (2026-01-19)
|
|
4
33
|
|
|
5
34
|
|
package/README.md
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
# az2aws
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Log in to AWS CLI using [Azure Active Directory](https://azure.microsoft.com) SSO. Supports MFA and places temporary credentials in the proper location for AWS CLI and SDKs.
|
|
9
9
|
|
|
10
10
|
## Installation
|
|
11
11
|
|
|
12
12
|
### mise (Recommended)
|
|
13
13
|
|
|
14
|
-
[mise](https://mise.jdx.dev/) is a
|
|
14
|
+
[mise](https://mise.jdx.dev/) is a version manager that can install az2aws directly.
|
|
15
15
|
|
|
16
16
|
Install mise:
|
|
17
17
|
|
|
@@ -66,12 +66,10 @@ Run az2aws with a volume mounted to your AWS configuration directory:
|
|
|
66
66
|
|
|
67
67
|
docker run --rm -it -v ~/.aws:/root/.aws az2aws/az2aws
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
You can also put the docker-launch.sh script into your bin directory for the az2aws command to function as usual:
|
|
69
|
+
You can also install the docker-launch.sh script to your PATH:
|
|
72
70
|
|
|
73
71
|
# Download the script (replace VERSION with a specific release tag, e.g., v1.0.0)
|
|
74
|
-
curl -o /tmp/az2aws https://raw.githubusercontent.com/
|
|
72
|
+
curl -o /tmp/az2aws https://raw.githubusercontent.com/kuma0128/az2aws/VERSION/docker-launch.sh -L
|
|
75
73
|
|
|
76
74
|
# IMPORTANT: Review the script before installing
|
|
77
75
|
cat /tmp/az2aws
|
|
@@ -80,9 +78,7 @@ You can also put the docker-launch.sh script into your bin directory for the az2
|
|
|
80
78
|
sudo mv /tmp/az2aws /usr/local/bin/az2aws
|
|
81
79
|
sudo chmod +x /usr/local/bin/az2aws
|
|
82
80
|
|
|
83
|
-
> **Security Note:** Always download from a specific release tag (not `main`) and review the script
|
|
84
|
-
|
|
85
|
-
Now just run `az2aws`.
|
|
81
|
+
> **Security Note:** Always download from a specific release tag (not `main`) and review the script before installing.
|
|
86
82
|
|
|
87
83
|
### Snap
|
|
88
84
|
|
|
@@ -104,13 +100,12 @@ https://snapcraft.io/az2aws
|
|
|
104
100
|
| `--enable-chrome-seamless-sso` | Enable Azure AD Seamless SSO |
|
|
105
101
|
| `--no-disable-extensions` | Keep browser extensions enabled |
|
|
106
102
|
| `--disable-gpu` | Disable GPU acceleration |
|
|
103
|
+
| `--version (-v)` | Show version number |
|
|
107
104
|
|
|
108
105
|
## Usage
|
|
109
106
|
|
|
110
107
|
### Configuration
|
|
111
108
|
|
|
112
|
-
#### AWS
|
|
113
|
-
|
|
114
109
|
To configure the az2aws client run:
|
|
115
110
|
|
|
116
111
|
az2aws --configure
|
|
@@ -119,22 +114,16 @@ You'll need your [Azure Tenant ID and the App ID URI](#getting-your-tenant-id-an
|
|
|
119
114
|
|
|
120
115
|
az2aws --configure --profile foo
|
|
121
116
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
To use az2aws with AWS GovCloud, set the `region` profile property in your ~/.aws/config to the one of the GovCloud regions:
|
|
117
|
+
#### GovCloud / China Region Support
|
|
125
118
|
|
|
126
|
-
-
|
|
127
|
-
- us-gov-east-1
|
|
119
|
+
Set the `region` in your ~/.aws/config to use non-standard AWS partitions:
|
|
128
120
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
To use az2aws with AWS China Cloud, set the `region` profile property in your ~/.aws/config to the China region:
|
|
132
|
-
|
|
133
|
-
- cn-north-1
|
|
121
|
+
- **GovCloud**: us-gov-west-1, us-gov-east-1
|
|
122
|
+
- **China**: cn-north-1, cn-northwest-1
|
|
134
123
|
|
|
135
124
|
#### Stay Logged In
|
|
136
125
|
|
|
137
|
-
|
|
126
|
+
Enable "Stay logged in" during configuration to use `--no-prompt` without storing passwords:
|
|
138
127
|
|
|
139
128
|
az2aws --no-prompt
|
|
140
129
|
az2aws --profile foo --no-prompt
|
|
@@ -147,6 +136,10 @@ You can set defaults via environment variables (use with `--no-prompt`):
|
|
|
147
136
|
- `AZURE_DEFAULT_USERNAME` / `AZURE_DEFAULT_PASSWORD` - Credentials
|
|
148
137
|
- `AZURE_DEFAULT_ROLE_ARN` / `AZURE_DEFAULT_DURATION_HOURS` - AWS role settings
|
|
149
138
|
|
|
139
|
+
When using `--no-prompt` with multiple available roles, you must set
|
|
140
|
+
`AZURE_DEFAULT_ROLE_ARN` (or configure `azure_default_role_arn`) so the CLI can
|
|
141
|
+
select a role without prompting.
|
|
142
|
+
|
|
150
143
|
To avoid storing passwords in bash history, use a leading space:
|
|
151
144
|
|
|
152
145
|
HISTCONTROL=ignoreboth
|
|
@@ -154,28 +147,26 @@ To avoid storing passwords in bash history, use a leading space:
|
|
|
154
147
|
|
|
155
148
|
#### Use an Existing Chrome Install and Profile
|
|
156
149
|
|
|
157
|
-
|
|
150
|
+
Use your own Chrome installation by setting these environment variables:
|
|
158
151
|
|
|
159
152
|
- `BROWSER_CHROME_BIN` - Path to Chrome executable
|
|
160
153
|
- `BROWSER_USER_DATA_DIR` - Chrome user data directory
|
|
161
154
|
- `BROWSER_PROFILE_DIR` - Chrome profile name (e.g., "Default")
|
|
162
155
|
|
|
163
|
-
Example
|
|
156
|
+
Example:
|
|
164
157
|
|
|
158
|
+
# macOS
|
|
165
159
|
export BROWSER_CHROME_BIN="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
166
|
-
export BROWSER_USER_DATA_DIR="/
|
|
167
|
-
export BROWSER_PROFILE_DIR="Default"
|
|
168
|
-
az2aws --mode gui --no-disable-extensions --no-sandbox
|
|
169
|
-
|
|
170
|
-
Example (Linux):
|
|
160
|
+
export BROWSER_USER_DATA_DIR="$HOME/Library/Application Support/Google/Chrome"
|
|
171
161
|
|
|
162
|
+
# Linux
|
|
172
163
|
export BROWSER_CHROME_BIN="/usr/bin/google-chrome"
|
|
173
|
-
export BROWSER_USER_DATA_DIR="
|
|
164
|
+
export BROWSER_USER_DATA_DIR="$HOME/.config/google-chrome"
|
|
165
|
+
|
|
166
|
+
# Common
|
|
174
167
|
export BROWSER_PROFILE_DIR="Default"
|
|
175
168
|
az2aws --mode gui --no-disable-extensions --no-sandbox
|
|
176
169
|
|
|
177
|
-
Using Chrome instead of Chromium allows you to use browser extensions such as password managers.
|
|
178
|
-
|
|
179
170
|
### Logging In
|
|
180
171
|
|
|
181
172
|
az2aws # Default profile
|
|
@@ -187,12 +178,23 @@ You'll be prompted for username, password, and MFA if required. After login, use
|
|
|
187
178
|
**Tips:**
|
|
188
179
|
- Set `AWS_PROFILE` env var instead of using `--profile`
|
|
189
180
|
- Use `--mode gui --disable-gpu` on VMs or if rendering fails
|
|
190
|
-
- Use `--no-sandbox` on Linux
|
|
191
181
|
- Set `https_proxy` env var for corporate proxy
|
|
192
182
|
|
|
183
|
+
#### Troubleshooting
|
|
184
|
+
|
|
185
|
+
If you see device compliance errors (e.g., "Device UnSecured Or Non-Compliant"),
|
|
186
|
+
Try:
|
|
187
|
+
`--mode gui` and use your system Chrome via `BROWSER_CHROME_BIN`.
|
|
188
|
+
|
|
189
|
+
If you see "Unable to recognize page state!", Azure's login pages may have
|
|
190
|
+
changed. Try:
|
|
191
|
+
|
|
192
|
+
- `--mode gui` or `--mode debug`
|
|
193
|
+
- Filing an issue with the screenshot (`az2aws-unrecognized-state.png`) to help maintainers update selectors
|
|
194
|
+
|
|
193
195
|
## Automation
|
|
194
196
|
|
|
195
|
-
Renew all profiles at once
|
|
197
|
+
Renew all profiles at once:
|
|
196
198
|
|
|
197
199
|
az2aws --all-profiles
|
|
198
200
|
az2aws --all-profiles --no-prompt # With "Stay logged in" enabled
|
|
@@ -201,21 +203,21 @@ Credentials are only refreshed if expiring within 11 minutes - safe to run as a
|
|
|
201
203
|
|
|
202
204
|
## Getting Your Tenant ID and App ID URI
|
|
203
205
|
|
|
204
|
-
|
|
206
|
+
Ask your Azure AD admin for these values, or extract them from myapps.microsoft.com:
|
|
205
207
|
|
|
206
208
|
1. Load the myapps.microsoft.com page.
|
|
207
|
-
2. Click the
|
|
208
|
-
3. In the window
|
|
209
|
+
2. Click the app tile for the login you want.
|
|
210
|
+
3. In the window that pops open, quickly copy the login.microsoftonline.com URL. (You can also use browser DevTools with "Preserve log" enabled to capture it.)
|
|
209
211
|
4. The GUID right after login.microsoftonline.com/ is the tenant ID.
|
|
210
212
|
5. Copy the SAMLRequest URL param.
|
|
211
213
|
6. Paste it into a URL decoder ([like this one](https://www.samltool.com/url.php)) and decode.
|
|
212
|
-
7. Paste the decoded output into
|
|
214
|
+
7. Paste the decoded output into a SAML deflated and encoded XML decoder ([like this one](https://www.samltool.com/decode.php)).
|
|
213
215
|
8. In the decoded XML output the value of the `Audience` tag is the App ID URI.
|
|
214
|
-
9.
|
|
216
|
+
9. Verify the tenant ID using the `tenantid` attribute in the XML.
|
|
215
217
|
|
|
216
218
|
## How It Works
|
|
217
219
|
|
|
218
|
-
|
|
220
|
+
az2aws uses [Puppeteer](https://github.com/GoogleChrome/puppeteer) to automate a Chromium browser for Azure AD login. It parses the SAML response and calls [AWS STS AssumeRoleWithSAML](http://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithSAML.html) to get temporary credentials.
|
|
219
221
|
|
|
220
222
|
## Troubleshooting
|
|
221
223
|
|
|
@@ -227,7 +229,7 @@ If login fails, try these in order:
|
|
|
227
229
|
|
|
228
230
|
## Support for Other Authentication Providers
|
|
229
231
|
|
|
230
|
-
|
|
232
|
+
This tool only supports Azure AD. Contributions for other SAML providers are welcome - open an issue on GitHub to discuss.
|
|
231
233
|
|
|
232
234
|
## Acknowledgements
|
|
233
235
|
|
package/issue/issues.md
CHANGED
|
@@ -726,4 +726,444 @@ Created an issues documentation file (`issue/issues.md`) to track and document a
|
|
|
726
726
|
**Benefits:**
|
|
727
727
|
- Centralized documentation of all project issues
|
|
728
728
|
- Easier onboarding for new contributors
|
|
729
|
-
- Clear tracking of issue status and priorities
|
|
729
|
+
- Clear tracking of issue status and priorities
|
|
730
|
+
|
|
731
|
+
---
|
|
732
|
+
|
|
733
|
+
## Performance Improvements
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
### Issue #57: Optimize keyboard input loop for clearing input fields
|
|
738
|
+
|
|
739
|
+
**Labels:** `performance`, `priority: high`
|
|
740
|
+
|
|
741
|
+
**Description:**
|
|
742
|
+
The current implementation sends 100 individual keyboard backspace events to clear input fields, causing unnecessary delay.
|
|
743
|
+
|
|
744
|
+
**Location:** `src/login.ts:97-99`, `src/login.ts:377-379`
|
|
745
|
+
|
|
746
|
+
**Current Code:**
|
|
747
|
+
```typescript
|
|
748
|
+
for (let i = 0; i < 100; i++) {
|
|
749
|
+
await page.keyboard.press("Backspace");
|
|
750
|
+
}
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
**Problem:**
|
|
754
|
+
- Sends 100 individual keyboard events causing unnecessary delay
|
|
755
|
+
- Each `press` call is an async operation executed serially
|
|
756
|
+
|
|
757
|
+
**Proposed Fix:**
|
|
758
|
+
Use `page.evaluate()` to clear input via DOM directly, or use `Ctrl+A` to select all then delete:
|
|
759
|
+
```typescript
|
|
760
|
+
// Option 1: Select all and delete
|
|
761
|
+
await page.keyboard.down('Control');
|
|
762
|
+
await page.keyboard.press('a');
|
|
763
|
+
await page.keyboard.up('Control');
|
|
764
|
+
await page.keyboard.press('Backspace');
|
|
765
|
+
|
|
766
|
+
// Option 2: Clear via DOM
|
|
767
|
+
await page.evaluate((selector) => {
|
|
768
|
+
const input = document.querySelector(selector) as HTMLInputElement;
|
|
769
|
+
if (input) input.value = '';
|
|
770
|
+
}, inputSelector);
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
**Expected Impact:** 100ms - 500ms reduction per input field
|
|
774
|
+
|
|
775
|
+
---
|
|
776
|
+
|
|
777
|
+
### Issue #58: Optimize page state polling loop
|
|
778
|
+
|
|
779
|
+
**Labels:** `performance`, `priority: high`
|
|
780
|
+
|
|
781
|
+
**Description:**
|
|
782
|
+
The state detection loop checks all 9 states from the beginning on every iteration, which is inefficient.
|
|
783
|
+
|
|
784
|
+
**Location:** `src/login.ts:814-874`
|
|
785
|
+
|
|
786
|
+
**Current Code:**
|
|
787
|
+
```typescript
|
|
788
|
+
while (true) {
|
|
789
|
+
if (samlResponseData) break;
|
|
790
|
+
|
|
791
|
+
let foundState = false;
|
|
792
|
+
for (let i = 0; i < states.length; i++) {
|
|
793
|
+
const state = states[i];
|
|
794
|
+
let selected;
|
|
795
|
+
try {
|
|
796
|
+
selected = await page.$(state.selector);
|
|
797
|
+
} catch (err) {
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (selected) {
|
|
802
|
+
foundState = true;
|
|
803
|
+
// ...
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
if (!foundState) {
|
|
809
|
+
totalUnrecognizedDelay += DELAY_ON_UNRECOGNIZED_PAGE;
|
|
810
|
+
await Bluebird.delay(DELAY_ON_UNRECOGNIZED_PAGE); // 1 second wait
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
**Problem:**
|
|
816
|
+
- Checks all 9 states from the beginning on every iteration
|
|
817
|
+
- Frequently occurring patterns may be at the end of the array
|
|
818
|
+
- Maximum 30 seconds polling with 1-second intervals
|
|
819
|
+
- Repeats all DOM operations when no state is found
|
|
820
|
+
|
|
821
|
+
**Proposed Fix:**
|
|
822
|
+
- Place frequently occurring states at the front of the array
|
|
823
|
+
- Cache the last matched state and prioritize it in the next check
|
|
824
|
+
- Consider combining multiple selectors with `waitForSelector`
|
|
825
|
+
|
|
826
|
+
**Expected Impact:** Potentially up to 30 seconds reduction in worst case scenarios
|
|
827
|
+
|
|
828
|
+
---
|
|
829
|
+
|
|
830
|
+
### Issue #59: Eliminate duplicate profile loading in loginAll
|
|
831
|
+
|
|
832
|
+
**Labels:** `performance`, `priority: medium`
|
|
833
|
+
|
|
834
|
+
**Description:**
|
|
835
|
+
In `loginAll()`, profile information is loaded from disk for each profile in the loop, causing redundant file I/O and INI parsing.
|
|
836
|
+
|
|
837
|
+
**Location:** `src/login.ts:527-556`, `src/login.ts:589-610`
|
|
838
|
+
|
|
839
|
+
**Current Code:**
|
|
840
|
+
```typescript
|
|
841
|
+
async loginAll(...) {
|
|
842
|
+
const profiles = await awsConfig.getAllProfileNames(); // Load 1
|
|
843
|
+
|
|
844
|
+
for (const profile of profiles) {
|
|
845
|
+
if (!forceRefresh && !(await awsConfig.isProfileAboutToExpireAsync(profile))) {
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
await this.loginAsync(profile, ...); // Calls _loadProfileAsync internally
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
**Problem:**
|
|
855
|
+
- Profile information is loaded from disk for each profile in the loop
|
|
856
|
+
- INI parsing is repeated multiple times
|
|
857
|
+
|
|
858
|
+
**Proposed Fix:**
|
|
859
|
+
- Cache profile information when `getAllProfileNames()` is called
|
|
860
|
+
- Or create a separate method to load all profiles at once
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
### Issue #60: Replace Lodash with native array methods
|
|
865
|
+
|
|
866
|
+
**Labels:** `performance`, `priority: low`
|
|
867
|
+
|
|
868
|
+
**Description:**
|
|
869
|
+
Lodash is used for small-scale operations where native array methods would be more efficient.
|
|
870
|
+
|
|
871
|
+
**Location:** `src/login.ts:175`, `src/login.ts:968`, `src/login.ts:979`, `src/login.ts:1005`
|
|
872
|
+
|
|
873
|
+
**Current Usage:**
|
|
874
|
+
```typescript
|
|
875
|
+
_.map(accounts, "message")
|
|
876
|
+
_.sortBy(_.map(roles, "roleArn"))
|
|
877
|
+
_.find(roles, ["roleArn", defaultRoleArn])
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
**Problem:**
|
|
881
|
+
- Lodash dependency for small-scale operations (typically <10 items)
|
|
882
|
+
- Native array methods are more efficient for these cases
|
|
883
|
+
|
|
884
|
+
**Proposed Fix:**
|
|
885
|
+
```typescript
|
|
886
|
+
// Replace _.map(accounts, "message")
|
|
887
|
+
accounts.map(a => a.message)
|
|
888
|
+
|
|
889
|
+
// Replace _.sortBy(_.map(roles, "roleArn"))
|
|
890
|
+
roles.map(r => r.roleArn).sort()
|
|
891
|
+
|
|
892
|
+
// Replace _.find(roles, ["roleArn", defaultRoleArn])
|
|
893
|
+
roles.find(r => r.roleArn === defaultRoleArn)
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
Consider removing Lodash from package.json if no longer needed elsewhere.
|
|
897
|
+
|
|
898
|
+
---
|
|
899
|
+
|
|
900
|
+
## Additional Bug Reports
|
|
901
|
+
|
|
902
|
+
---
|
|
903
|
+
|
|
904
|
+
### Issue #61: Incomplete error handling in page navigation
|
|
905
|
+
|
|
906
|
+
**Labels:** `bug`, `priority: high`
|
|
907
|
+
|
|
908
|
+
**Description:**
|
|
909
|
+
Page navigation errors are logged but not properly handled, allowing the process to continue in an undefined state.
|
|
910
|
+
|
|
911
|
+
**Location:** `src/login.ts:803-809`
|
|
912
|
+
|
|
913
|
+
**Current Code:**
|
|
914
|
+
```typescript
|
|
915
|
+
try {
|
|
916
|
+
if (headless || (!headless && cliProxy)) {
|
|
917
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
918
|
+
} else {
|
|
919
|
+
await page.waitForNavigation({ waitUntil: "networkidle0" });
|
|
920
|
+
}
|
|
921
|
+
} catch (err) {
|
|
922
|
+
if (err instanceof Error) {
|
|
923
|
+
debug(`Error occured during loading the first page: ${err.message}`);
|
|
924
|
+
// Error is swallowed, logic continues
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
**Problem:**
|
|
930
|
+
- Error is only logged, not thrown or handled
|
|
931
|
+
- May continue in an undefined state when redirect fails
|
|
932
|
+
- Typo: "occured" should be "occurred"
|
|
933
|
+
|
|
934
|
+
**Proposed Fix:**
|
|
935
|
+
```typescript
|
|
936
|
+
try {
|
|
937
|
+
if (headless || (!headless && cliProxy)) {
|
|
938
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
939
|
+
} else {
|
|
940
|
+
await page.waitForNavigation({ waitUntil: "networkidle0" });
|
|
941
|
+
}
|
|
942
|
+
} catch (err) {
|
|
943
|
+
if (err instanceof Error) {
|
|
944
|
+
debug(`Error occurred during loading the first page: ${err.message}`);
|
|
945
|
+
throw new CLIError(`Failed to load login page: ${err.message}`);
|
|
946
|
+
}
|
|
947
|
+
throw err;
|
|
948
|
+
}
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
---
|
|
952
|
+
|
|
953
|
+
### Issue #62: Missing NaN validation in duration hours input
|
|
954
|
+
|
|
955
|
+
**Labels:** `bug`, `priority: medium`
|
|
956
|
+
|
|
957
|
+
**Description:**
|
|
958
|
+
The duration hours input validation does not check for NaN values when converting string input to number.
|
|
959
|
+
|
|
960
|
+
**Location:** `src/configureProfileAsync.ts:50-56`
|
|
961
|
+
|
|
962
|
+
**Current Code:**
|
|
963
|
+
```typescript
|
|
964
|
+
validate: (input): boolean | string => {
|
|
965
|
+
input = Number(input);
|
|
966
|
+
if (input > 0 && input <= 12) return true;
|
|
967
|
+
return "Duration hours must be between 0 and 12";
|
|
968
|
+
},
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
**Problem:**
|
|
972
|
+
- Only validates after String to Number conversion
|
|
973
|
+
- No NaN check - `Number("abc")` returns NaN which fails the condition silently
|
|
974
|
+
- Error message says "between 0 and 12" but code checks `> 0` (exclusive)
|
|
975
|
+
|
|
976
|
+
**Proposed Fix:**
|
|
977
|
+
```typescript
|
|
978
|
+
validate: (input): boolean | string => {
|
|
979
|
+
const num = Number(input);
|
|
980
|
+
if (Number.isNaN(num)) return "Please enter a valid number";
|
|
981
|
+
if (num > 0 && num <= 12) return true;
|
|
982
|
+
return "Duration hours must be greater than 0 and at most 12";
|
|
983
|
+
},
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
---
|
|
987
|
+
|
|
988
|
+
### Issue #63: Fixed delay for browser initialization is environment-dependent
|
|
989
|
+
|
|
990
|
+
**Labels:** `bug`, `priority: medium`
|
|
991
|
+
|
|
992
|
+
**Description:**
|
|
993
|
+
A fixed 200ms delay is used to wait for browser initialization, which may be insufficient in slower environments.
|
|
994
|
+
|
|
995
|
+
**Location:** `src/login.ts:750`
|
|
996
|
+
|
|
997
|
+
**Current Code:**
|
|
998
|
+
```typescript
|
|
999
|
+
browser = await puppeteer.launch(launchParams);
|
|
1000
|
+
|
|
1001
|
+
// Wait for a bit as sometimes the browser isn't ready.
|
|
1002
|
+
await Bluebird.delay(200);
|
|
1003
|
+
|
|
1004
|
+
const pages = await browser.pages();
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
**Problem:**
|
|
1008
|
+
- 200ms fixed delay is environment-dependent
|
|
1009
|
+
- May cause instability in CI environments or slower machines
|
|
1010
|
+
- May cause unnecessary delay in faster environments
|
|
1011
|
+
|
|
1012
|
+
**Proposed Fix:**
|
|
1013
|
+
Use a more reliable wait mechanism for browser initialization:
|
|
1014
|
+
```typescript
|
|
1015
|
+
browser = await puppeteer.launch(launchParams);
|
|
1016
|
+
|
|
1017
|
+
// Wait for browser to be ready
|
|
1018
|
+
const pages = await browser.pages();
|
|
1019
|
+
if (pages.length === 0) {
|
|
1020
|
+
// Wait for default page to be created
|
|
1021
|
+
await browser.waitForTarget(target => target.type() === 'page');
|
|
1022
|
+
}
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
---
|
|
1026
|
+
|
|
1027
|
+
### Issue #64: Event listener memory leak risk in SAML response handling
|
|
1028
|
+
|
|
1029
|
+
**Labels:** `bug`, `priority: medium`
|
|
1030
|
+
|
|
1031
|
+
**Description:**
|
|
1032
|
+
The request event listener for capturing SAML responses is not explicitly cleaned up after use.
|
|
1033
|
+
|
|
1034
|
+
**Location:** `src/login.ts:761-790`
|
|
1035
|
+
|
|
1036
|
+
**Current Code:**
|
|
1037
|
+
```typescript
|
|
1038
|
+
const samlResponsePromise = new Promise((resolve) => {
|
|
1039
|
+
page.on("request", (req: HTTPRequest) => {
|
|
1040
|
+
// Event listener may remain registered
|
|
1041
|
+
const reqUrl = req.url();
|
|
1042
|
+
if (reqUrl === AWS_SAML_ENDPOINT || reqUrl === AWS_GOV_SAML_ENDPOINT || reqUrl === AWS_CN_SAML_ENDPOINT) {
|
|
1043
|
+
// ...
|
|
1044
|
+
resolve(samlResponse);
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
});
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
**Problem:**
|
|
1051
|
+
- Event listener is not explicitly cleaned up
|
|
1052
|
+
- Potential memory leak if page is reused or not properly closed
|
|
1053
|
+
|
|
1054
|
+
**Proposed Fix:**
|
|
1055
|
+
```typescript
|
|
1056
|
+
const samlResponsePromise = new Promise((resolve) => {
|
|
1057
|
+
const requestHandler = (req: HTTPRequest) => {
|
|
1058
|
+
const reqUrl = req.url();
|
|
1059
|
+
if (reqUrl === AWS_SAML_ENDPOINT || reqUrl === AWS_GOV_SAML_ENDPOINT || reqUrl === AWS_CN_SAML_ENDPOINT) {
|
|
1060
|
+
// ...
|
|
1061
|
+
page.off("request", requestHandler); // Clean up listener
|
|
1062
|
+
resolve(samlResponse);
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
page.on("request", requestHandler);
|
|
1066
|
+
});
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
Or use `page.once()` if appropriate for the use case.
|
|
1070
|
+
|
|
1071
|
+
---
|
|
1072
|
+
|
|
1073
|
+
### Issue #65: Typo in error message
|
|
1074
|
+
|
|
1075
|
+
**Labels:** `bug`, `priority: low`
|
|
1076
|
+
|
|
1077
|
+
**Description:**
|
|
1078
|
+
There is a typo in the error debug message.
|
|
1079
|
+
|
|
1080
|
+
**Location:** `src/login.ts:806`
|
|
1081
|
+
|
|
1082
|
+
**Current:** `"Error occured during loading the first page"`
|
|
1083
|
+
**Should be:** `"Error occurred during loading the first page"`
|
|
1084
|
+
|
|
1085
|
+
**Proposed Fix:**
|
|
1086
|
+
```typescript
|
|
1087
|
+
debug(`Error occurred during loading the first page: ${err.message}`);
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
---
|
|
1091
|
+
|
|
1092
|
+
## Code Quality Improvements
|
|
1093
|
+
|
|
1094
|
+
---
|
|
1095
|
+
|
|
1096
|
+
### Issue #66: Reduce `any` type usage and eslint-disable comments
|
|
1097
|
+
|
|
1098
|
+
**Labels:** `code-quality`, `priority: medium`
|
|
1099
|
+
|
|
1100
|
+
**Description:**
|
|
1101
|
+
There are several places where `any` type and `eslint-disable` comments are used, reducing type safety.
|
|
1102
|
+
|
|
1103
|
+
**Locations:**
|
|
1104
|
+
- `src/awsConfig.ts:149` - `any` type for parsed INI
|
|
1105
|
+
- `src/login.ts:141-144` - eslint-disable comment
|
|
1106
|
+
|
|
1107
|
+
**Current Code:**
|
|
1108
|
+
```typescript
|
|
1109
|
+
// awsConfig.ts:149
|
|
1110
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1111
|
+
const parsedIni: any = ini.parse(data);
|
|
1112
|
+
|
|
1113
|
+
// login.ts:141-144
|
|
1114
|
+
const aadTileMessage: string = await page.evaluate(
|
|
1115
|
+
// eslint-disable-next-line
|
|
1116
|
+
(a) => a?.textContent ?? "",
|
|
1117
|
+
aadTile
|
|
1118
|
+
);
|
|
1119
|
+
```
|
|
1120
|
+
|
|
1121
|
+
**Proposed Fix:**
|
|
1122
|
+
- Define proper TypeScript interfaces for INI parsing results
|
|
1123
|
+
- Use type guards instead of eslint-disable comments
|
|
1124
|
+
- Consider using a typed INI parser or create proper type definitions
|
|
1125
|
+
|
|
1126
|
+
---
|
|
1127
|
+
|
|
1128
|
+
### Issue #67: Add missing test coverage for critical functions
|
|
1129
|
+
|
|
1130
|
+
**Labels:** `testing`, `priority: medium`
|
|
1131
|
+
|
|
1132
|
+
**Description:**
|
|
1133
|
+
Several critical functions lack test coverage.
|
|
1134
|
+
|
|
1135
|
+
**Location:** `src/login.test.ts`
|
|
1136
|
+
|
|
1137
|
+
**Missing Tests:**
|
|
1138
|
+
- `_performLoginAsync()` - the most complex function with browser automation
|
|
1139
|
+
- `_parseRolesFromSamlResponse()` - SAML parsing logic
|
|
1140
|
+
- Edge cases: empty SAML response, zero roles, malformed XML, etc.
|
|
1141
|
+
|
|
1142
|
+
**Proposed Tests:**
|
|
1143
|
+
```typescript
|
|
1144
|
+
describe("login._performLoginAsync", () => {
|
|
1145
|
+
// Mock puppeteer browser behavior
|
|
1146
|
+
// Test SAML session completion sequence
|
|
1147
|
+
});
|
|
1148
|
+
|
|
1149
|
+
describe("login._parseRolesFromSamlResponse", () => {
|
|
1150
|
+
it("should parse valid SAML response with multiple roles", () => {});
|
|
1151
|
+
it("should handle empty SAML response", () => {});
|
|
1152
|
+
it("should handle special characters in role names", () => {});
|
|
1153
|
+
it("should handle UTF-8 encoded content", () => {});
|
|
1154
|
+
});
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
---
|
|
1158
|
+
|
|
1159
|
+
### [RESOLVED] Issue #68: Prettier formatting issues in login files
|
|
1160
|
+
|
|
1161
|
+
**Labels:** `code-quality`, `priority: low`
|
|
1162
|
+
|
|
1163
|
+
**Description:**
|
|
1164
|
+
Prettier detected code style issues in `src/login.ts` and `src/login.test.ts` that caused `yarn lint` to fail.
|
|
1165
|
+
|
|
1166
|
+
**Location:** `src/login.ts`, `src/login.test.ts`
|
|
1167
|
+
|
|
1168
|
+
**Resolution:**
|
|
1169
|
+
Fixed by running `yarn prettier --write` on the affected files.
|