Skip to content

Commit 084e6b6

Browse files
authored
release(required): Amplify JS release (#14649)
2 parents 3a1b5a7 + 94352c7 commit 084e6b6

File tree

48 files changed

+1054
-1444
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1054
-1444
lines changed

.gitallowed

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# The following regexes are exceptions for git-secrets - https://github.com/awslabs/git-secrets
2+
3+
# The only AWS account number allowed to be used in tests
4+
ACCOUNT_ID = '123456789012';

.github/dependency-review/dependency-review-config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ allow-licenses:
1010
- 'BSL-1.0'
1111
- 'CC-BY-3.0'
1212
- 'CC-BY-4.0'
13+
- 'CC-BY-SA-4.0'
1314
- 'CC0-1.0'
1415
- 'curl'
1516
- 'ISC'
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Git Secrets Check
2+
on: workflow_call
3+
4+
jobs:
5+
git_secrets_check:
6+
name: Scan for secrets
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Checkout repository
10+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
11+
with:
12+
path: amplify-js
13+
14+
- name: Install git-secrets
15+
run: |
16+
git clone https://github.com/awslabs/git-secrets.git
17+
cd git-secrets
18+
sudo make install
19+
20+
- name: Register AWS patterns and scan
21+
working-directory: ./amplify-js
22+
run: |
23+
git secrets --register-aws
24+
# Scan only the files in the current checkout (PR merge commit)
25+
git secrets --scan

.github/workflows/pr.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ jobs:
4343
dependency-review:
4444
needs: prebuild
4545
uses: ./.github/workflows/callable-dependency-review.yml
46+
git-secrets-check:
47+
uses: ./.github/workflows/callable-git-secrets-check.yml
4648
all-unit-tests-pass:
4749
name: Unit and Bundle tests have passed
4850
needs:
@@ -52,6 +54,7 @@ jobs:
5254
- github-actions-test
5355
- tsc-compliance-test
5456
- dependency-review
57+
- git-secrets-check
5558
runs-on: ubuntu-latest
5659
if: success() # only run when all checks have passed
5760
# store success output flag for ci job

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ packages/**/esm/
1111
packages/**/cjs/
1212
**/.DS_Store
1313
.vscode
14+
.kiro
1415
.idea
1516
*.log
1617
.npm/

.husky/pre-push

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env sh
2+
3+
# Pre-push hook to scan for secrets using git-secrets
4+
# This prevents accidentally pushing AWS credentials or other secrets
5+
6+
# Check if git-secrets is installed
7+
if ! command -v git-secrets >/dev/null 2>&1; then
8+
echo ""
9+
echo "ERROR: git-secrets is not installed."
10+
echo ""
11+
echo "Please install git-secrets to continue:"
12+
echo ""
13+
echo " macOS: brew install git-secrets"
14+
echo " Linux: See https://github.com/awslabs/git-secrets#installing-git-secrets"
15+
echo " Windows: See https://github.com/awslabs/git-secrets#installing-git-secrets"
16+
echo ""
17+
echo "After installation, register AWS patterns:"
18+
echo " git secrets --register-aws"
19+
echo ""
20+
exit 1
21+
fi
22+
23+
# Run git-secrets scan and propagate exit code
24+
git secrets --scan

CONTRIBUTING.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Whether it's a bug report, new feature, correction, or additional documentation,
88
- [Our Design](#our-design)
99
- [Development Process](#development-process)
1010
- [Setting up for local development](#setting-up-for-local-development)
11+
- [Setting up git-secrets](#setting-up-git-secrets)
1112
- [Architecture of the codebase](#architecture-of-the-codebase)
1213
- [Steps towards contributions](#steps-towards-contributions)
1314
- [Bug Reports](#bug-reports)
@@ -68,6 +69,74 @@ yarn build
6869

6970
> Note: Make sure to always [sync your fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork) with main branch of `amplify-js`
7071
72+
## Setting up git-secrets
73+
74+
This repository uses [git-secrets](https://github.com/awslabs/git-secrets) to prevent accidentally pushing AWS credentials or other secrets. A pre-push hook will scan your commits before pushing to the remote repository.
75+
76+
### Installing git-secrets
77+
78+
**macOS (using Homebrew):**
79+
80+
```bash
81+
brew install git-secrets
82+
```
83+
84+
**Linux (Debian/Ubuntu):**
85+
86+
```bash
87+
sudo apt-get install git-secrets
88+
```
89+
90+
**Linux (manual installation):**
91+
92+
```bash
93+
git clone https://github.com/awslabs/git-secrets.git
94+
cd git-secrets
95+
sudo make install
96+
```
97+
98+
**Windows (manual installation):**
99+
100+
1. Clone the repository: `git clone https://github.com/awslabs/git-secrets.git`
101+
2. Add the `git-secrets` directory to your PATH
102+
3. Alternatively, copy `git-secrets` to a directory already in your PATH
103+
104+
### Registering AWS patterns
105+
106+
After installing git-secrets, register the AWS secret patterns in your local repository:
107+
108+
```bash
109+
git secrets --register-aws
110+
```
111+
112+
This registers patterns to detect:
113+
114+
- AWS Access Key IDs (e.g., `AKIAIOSFODNN7EXAMPLE`)
115+
- AWS Secret Access Keys
116+
- AWS Session Tokens
117+
118+
You can verify the registered patterns with:
119+
120+
```bash
121+
git secrets --list
122+
```
123+
124+
### Handling false positives
125+
126+
If git-secrets flags a legitimate string as a potential secret (false positive), you can add an allowed pattern:
127+
128+
```bash
129+
# Allow a specific pattern
130+
git secrets --add --allowed 'AKIAIOSFODNN7EXAMPLE'
131+
132+
# Allow patterns matching a regex
133+
git secrets --add --allowed 'my-test-pattern.*'
134+
```
135+
136+
Allowed patterns are stored in `.git/config` and apply only to your local repository.
137+
138+
> **Note:** The pre-push hook will block pushes if git-secrets is not installed. Please install and configure git-secrets before contributing.
139+
71140
## Architecture of the codebase
72141

73142
Amplify JS is a monorepo built with `Yarn` and `Lerna`. All the categories of Amplify live within the `packages` directory in the root. Each category inside packages has its own `src/` and `package.json`.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"publish:verdaccio": "lerna publish --canary --force-publish --no-push --dist-tag=unstable --preid=unstable --yes",
3535
"generate-metadata": "git rev-parse --short HEAD > packages/core/metadata && git commit -am 'chore(release): Set core metadata [skip release]'",
3636
"ts-coverage": "lerna run ts-coverage",
37-
"prepare": "husky && ./scripts/set-preid-versions.sh"
37+
"prepare": "husky && ./scripts/setup-git-secrets.sh && ./scripts/set-preid-versions.sh"
3838
},
3939
"workspaces": {
4040
"packages": [
@@ -136,6 +136,7 @@
136136
"webpack-cli": "^5.0.0"
137137
},
138138
"resolutions": {
139+
"@react-native-community/cli": "^18.0.1",
139140
"@types/babel__traverse": "7.20.0",
140141
"path-scurry": "1.10.0",
141142
"**/glob/minipass": "6.0.2",
@@ -146,9 +147,11 @@
146147
"**/brace-expansion": "1.1.12",
147148
"**/on-headers": "1.1.0",
148149
"**/form-data": "4.0.4",
149-
"tmp": "^0.2.4"
150+
"tmp": "^0.2.4",
151+
"js-yaml": "4.1.1"
150152
},
151153
"overrides": {
154+
"js-yaml": "4.1.1",
152155
"tar": "6.2.1",
153156
"cross-spawn": "7.0.5",
154157
"brace-expansion": "1.1.12",

packages/api-rest/__tests__/apis/common/publicApis.test.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,5 +681,113 @@ describe('public APIs', () => {
681681
expect(result).toEqual({ retryable: false });
682682
});
683683
});
684+
685+
describe('defaultAuthMode option', () => {
686+
it('should skip credential resolution when defaultAuthMode is "none"', async () => {
687+
mockFetchAuthSession.mockClear();
688+
689+
await fn(mockAmplifyInstance, {
690+
apiName: 'restApi1',
691+
path: '/public',
692+
options: {
693+
defaultAuthMode: 'none',
694+
},
695+
}).response;
696+
697+
expect(mockFetchAuthSession).not.toHaveBeenCalled();
698+
expect(mockUnauthenticatedHandler).toHaveBeenCalled();
699+
expect(mockAuthenticatedHandler).not.toHaveBeenCalled();
700+
});
701+
702+
it('should resolve credentials when defaultAuthMode is "iam"', async () => {
703+
mockFetchAuthSession.mockResolvedValue({
704+
credentials: {
705+
accessKeyId: 'test-key',
706+
secretAccessKey: 'test-secret',
707+
},
708+
});
709+
710+
await fn(mockAmplifyInstance, {
711+
apiName: 'restApi1',
712+
path: '/private',
713+
options: {
714+
defaultAuthMode: 'iam',
715+
},
716+
}).response;
717+
718+
expect(mockFetchAuthSession).toHaveBeenCalled();
719+
expect(mockAuthenticatedHandler).toHaveBeenCalled();
720+
});
721+
722+
it('should maintain default behavior when no defaultAuthMode specified', async () => {
723+
mockFetchAuthSession.mockResolvedValue({
724+
credentials: null,
725+
});
726+
727+
await fn(mockAmplifyInstance, {
728+
apiName: 'restApi1',
729+
path: '/endpoint',
730+
}).response;
731+
732+
expect(mockFetchAuthSession).toHaveBeenCalled();
733+
expect(mockUnauthenticatedHandler).toHaveBeenCalled();
734+
});
735+
736+
it('should use global defaultAuthMode configuration when no local defaultAuthMode is specified', async () => {
737+
const mockAmplifyWithGlobalConfig = {
738+
...mockAmplifyInstance,
739+
libraryOptions: {
740+
...mockAmplifyInstance.libraryOptions,
741+
API: {
742+
...mockAmplifyInstance.libraryOptions?.API,
743+
REST: {
744+
defaultAuthMode: 'none' as const,
745+
},
746+
},
747+
},
748+
} as any as AmplifyClassV6;
749+
750+
mockFetchAuthSession.mockClear();
751+
752+
await fn(mockAmplifyWithGlobalConfig, {
753+
apiName: 'restApi1',
754+
path: '/public',
755+
}).response;
756+
757+
expect(mockFetchAuthSession).not.toHaveBeenCalled();
758+
expect(mockUnauthenticatedHandler).toHaveBeenCalled();
759+
expect(mockAuthenticatedHandler).not.toHaveBeenCalled();
760+
});
761+
762+
it('should override global defaultAuthMode with local defaultAuthMode configuration', async () => {
763+
const mockAmplifyWithGlobalConfig = {
764+
...mockAmplifyInstance,
765+
libraryOptions: {
766+
...mockAmplifyInstance.libraryOptions,
767+
API: {
768+
...mockAmplifyInstance.libraryOptions?.API,
769+
REST: {
770+
defaultAuthMode: 'none' as const,
771+
},
772+
},
773+
},
774+
} as any as AmplifyClassV6;
775+
776+
mockFetchAuthSession.mockClear();
777+
mockFetchAuthSession.mockResolvedValue({ credentials });
778+
779+
await fn(mockAmplifyWithGlobalConfig, {
780+
apiName: 'restApi1',
781+
path: '/private',
782+
options: {
783+
defaultAuthMode: 'iam',
784+
},
785+
}).response;
786+
787+
expect(mockFetchAuthSession).toHaveBeenCalled();
788+
expect(mockAuthenticatedHandler).toHaveBeenCalled();
789+
expect(mockUnauthenticatedHandler).not.toHaveBeenCalled();
790+
});
791+
});
684792
});
685793
});

packages/api-rest/src/apis/common/transferHandler.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ import {
1111
import {
1212
AWSCredentials,
1313
DocumentType,
14+
RESTAuthMode,
1415
RetryStrategy,
1516
} from '@aws-amplify/core/internals/utils';
1617

1718
import {
1819
logger,
1920
parseRestApiServiceError,
2021
parseSigningInfo,
22+
resolveLibraryOptions,
2123
} from '../../utils';
2224
import { resolveHeaders } from '../../utils/resolveHeaders';
2325
import { RestApiResponse, SigningServiceInfo } from '../../types';
@@ -30,6 +32,7 @@ type HandlerOptions = Omit<HttpRequest, 'body' | 'headers'> & {
3032
headers?: Headers;
3133
withCredentials?: boolean;
3234
retryStrategy?: RetryStrategy;
35+
defaultAuthMode?: RESTAuthMode;
3336
};
3437

3538
type RetryDecider = RetryOptions['retryDecider'];
@@ -75,19 +78,29 @@ export const transferHandler = async (
7578
method,
7679
body: resolvedBody,
7780
};
81+
const {
82+
retryStrategy: libraryRetryStrategy,
83+
defaultAuthMode: libraryDefaultAuthMode,
84+
} = resolveLibraryOptions(amplify);
7885
const baseOptions = {
7986
retryDecider: getRetryDeciderFromStrategy(
80-
retryStrategy ?? amplify?.libraryOptions?.API?.REST?.retryStrategy,
87+
retryStrategy ?? libraryRetryStrategy,
8188
),
8289
computeDelay: jitteredBackoff,
8390
withCrossDomainCredentials: withCredentials,
8491
abortSignal,
8592
};
8693

87-
const isIamAuthApplicable = iamAuthApplicable(request, signingServiceInfo);
94+
const defaultAuthMode = options.defaultAuthMode ?? libraryDefaultAuthMode;
95+
96+
let credentials: AWSCredentials | null = null;
97+
if (defaultAuthMode !== 'none') {
98+
credentials = await resolveCredentials(amplify);
99+
}
88100

89101
let response: RestApiResponse;
90-
const credentials = await resolveCredentials(amplify);
102+
const isIamAuthApplicable = iamAuthApplicable(request, signingServiceInfo);
103+
91104
if (isIamAuthApplicable && credentials) {
92105
const signingInfoFromUrl = parseSigningInfo(url);
93106
const signingService =

0 commit comments

Comments
 (0)