Skip to content

Commit de90deb

Browse files
ShadowCat567Vieltojarvi
andauthored
EACCES: Permission Denied Errors (#2468)
* EACCES errors * update message * changeset * write to outputs with mode = 600 * add console statement for testing * testing * added error messaging * testing * removed testing console statements * changed message * updated error catching * added tests to profile-controller and handling for windows users * removed windows handling * changed chmod to chmodSync * test for client config writer --------- Co-authored-by: Vieltojarvi <[email protected]>
1 parent 8f04c9f commit de90deb

File tree

5 files changed

+150
-3
lines changed

5 files changed

+150
-3
lines changed

.changeset/chatty-jars-drum.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@aws-amplify/client-config': patch
3+
'@aws-amplify/backend-cli': patch
4+
---
5+
6+
Added catch blocks for EACCES Errors

packages/cli/src/commands/configure/profile_controller.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { ProfileController } from './profile_controller.js';
55
import assert from 'node:assert';
66
import { loadSharedConfigFiles } from '@smithy/shared-ini-file-loader';
77
import { EOL } from 'node:os';
8+
import { chmodSync } from 'node:fs';
9+
import { AmplifyUserError } from '@aws-amplify/platform-core';
810

911
const testAccessKeyId = 'testAccessKeyId';
1012
const testSecretAccessKey = 'testSecretAccessKey';
@@ -218,6 +220,64 @@ void describe('profile controller', () => {
218220
);
219221
});
220222

223+
void it('throws error if config file already exists and is missing read permissions', async () => {
224+
if (process.platform.startsWith('win')) {
225+
// Windows does not have the same behavior when files are missing permissions
226+
return;
227+
}
228+
229+
const expectedErr = new AmplifyUserError('PermissionsError', {
230+
message: `You do not have the permissions to read this file: ${configFilePath}.`,
231+
resolution: `Ensure that you have the right permissions to read from ${configFilePath}.`,
232+
});
233+
chmodSync(configFilePath, 0o000);
234+
await assert.rejects(
235+
async () =>
236+
await profileController.createOrAppendAWSFiles({
237+
profile: testProfile2,
238+
region: testRegion2,
239+
accessKeyId: testAccessKeyId2,
240+
secretAccessKey: testSecretAccessKey2,
241+
}),
242+
(error: AmplifyUserError) => {
243+
assert.strictEqual(error.name, expectedErr.name);
244+
assert.strictEqual(error.message, expectedErr.message);
245+
assert.strictEqual(error.resolution, expectedErr.resolution);
246+
return true;
247+
}
248+
);
249+
});
250+
251+
void it('throws error if config file already exists and is missing write permissions', async () => {
252+
if (process.platform.startsWith('win')) {
253+
// Windows does not have the same behavior when files are missing permissions
254+
return;
255+
}
256+
257+
const expectedErr = new AmplifyUserError('PermissionsError', {
258+
message: `You do not have the permissions to write to this file: ${configFilePath}`,
259+
resolution: `Ensure that you have the right permissions to write to ${configFilePath}.`,
260+
});
261+
262+
chmodSync(configFilePath, 0o444);
263+
264+
await assert.rejects(
265+
async () =>
266+
await profileController.createOrAppendAWSFiles({
267+
profile: testProfile2,
268+
region: testRegion2,
269+
accessKeyId: testAccessKeyId2,
270+
secretAccessKey: testSecretAccessKey2,
271+
}),
272+
(error: AmplifyUserError) => {
273+
assert.strictEqual(error.name, expectedErr.name);
274+
assert.strictEqual(error.message, expectedErr.message);
275+
assert.strictEqual(error.resolution, expectedErr.resolution);
276+
return true;
277+
}
278+
);
279+
});
280+
221281
void it('creates directory if does not exist', async () => {
222282
// delete directory
223283
await fs.rm(testDir, { recursive: true, force: true });

packages/cli/src/commands/configure/profile_controller.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { EOL } from 'os';
88
import fs from 'fs/promises';
99
import path from 'path';
1010
import { existsSync } from 'fs';
11+
import { AmplifyUserError } from '@aws-amplify/platform-core';
1112

1213
/**
1314
* Options for the profile configuration.
@@ -77,7 +78,23 @@ export class ProfileController {
7778
: `[profile ${options.profile}]${EOL}`;
7879
configData += `region = ${options.region}${EOL}`;
7980

80-
await fs.appendFile(filePath, configData, { mode: '600' });
81+
try {
82+
await fs.appendFile(filePath, configData, { mode: '600' });
83+
} catch (err) {
84+
const error = err as Error;
85+
if (error.message.includes('EACCES')) {
86+
throw new AmplifyUserError(
87+
'PermissionsError',
88+
{
89+
message: `You do not have the permissions to write to this file: ${filePath}`,
90+
resolution: `Ensure that you have the right permissions to write to ${filePath}.`,
91+
},
92+
error
93+
);
94+
} else {
95+
throw error;
96+
}
97+
}
8198

8299
// validate after write. It is to ensure this function is compatible with the current AWS format.
83100
const profileData = await loadSharedConfigFiles({
@@ -135,7 +152,18 @@ export class ProfileController {
135152
// file doesn't exists
136153
return true;
137154
}
138-
throw err;
155+
if (error.message.includes('EACCES')) {
156+
throw new AmplifyUserError(
157+
'PermissionsError',
158+
{
159+
message: `You do not have the permissions to read this file: ${filePath}.`,
160+
resolution: `Ensure that you have the right permissions to read from ${filePath}.`,
161+
},
162+
error
163+
);
164+
} else {
165+
throw err;
166+
}
139167
}
140168
};
141169
}

packages/client-config/src/client-config-writer/client_config_writer.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from '../client-config-types/client_config.js';
1515
import { ClientConfigFormatterLegacy } from './client_config_formatter_legacy.js';
1616
import { randomUUID } from 'crypto';
17+
import { AmplifyUserError } from '@aws-amplify/platform-core';
1718

1819
void describe('client config writer', () => {
1920
const sampleRegion = 'test_region';
@@ -180,4 +181,38 @@ void describe('client config writer', () => {
180181
ClientConfigFormat.JSON
181182
);
182183
});
184+
185+
void it('throws an error when targetFile exists and is missing write permissions', async () => {
186+
const outDir = '/foo/bar';
187+
const targetFile = '/foo/bar/baz';
188+
const format = ClientConfigFormat.MJS;
189+
const expectedErr = new AmplifyUserError('PermissionsError', {
190+
message: `You do not have the permissions to write to this file: ${targetFile}`,
191+
resolution: `Ensure that you have the right permissions to write to ${targetFile}.`,
192+
});
193+
194+
fspMock.writeFile.mock.mockImplementationOnce(() =>
195+
Promise.reject(new Error('EACCES: Permission denied'))
196+
);
197+
pathResolverMock.mock.mockImplementation(() => Promise.resolve(targetFile));
198+
nameResolverMock.mock.mockImplementation(
199+
() => ClientConfigFileBaseName.DEFAULT
200+
);
201+
202+
await assert.rejects(
203+
async () =>
204+
await clientConfigWriter.writeClientConfig(
205+
clientConfig,
206+
DEFAULT_CLIENT_CONFIG_VERSION,
207+
outDir,
208+
format
209+
),
210+
(error: AmplifyUserError) => {
211+
assert.strictEqual(error.name, expectedErr.name);
212+
assert.strictEqual(error.message, expectedErr.message);
213+
assert.strictEqual(error.resolution, expectedErr.resolution);
214+
return true;
215+
}
216+
);
217+
});
183218
});

packages/client-config/src/client-config-writer/client_config_writer.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
GenerateClientConfigToFileResult,
99
} from '../client-config-types/client_config.js';
1010
import { ClientConfigFormatter } from './client_config_formatter.js';
11+
import { AmplifyUserError } from '@aws-amplify/platform-core';
1112

1213
export type ClientConfigPathResolver = (
1314
fileName: ClientConfigFileBaseName,
@@ -47,7 +48,24 @@ export class ClientConfigWriter {
4748
format
4849
);
4950
const fileContent = this.formatter.format(clientConfig, format);
50-
await this.fsp.writeFile(targetPath, fileContent);
51+
52+
try {
53+
await this.fsp.writeFile(targetPath, fileContent);
54+
} catch (err) {
55+
const error = err as Error;
56+
if (error.message.includes('EACCES')) {
57+
throw new AmplifyUserError(
58+
'PermissionsError',
59+
{
60+
message: `You do not have the permissions to write to this file: ${targetPath}`,
61+
resolution: `Ensure that you have the right permissions to write to ${targetPath}.`,
62+
},
63+
error
64+
);
65+
} else {
66+
throw error;
67+
}
68+
}
5169

5270
return {
5371
filesWritten: [path.relative(process.cwd(), targetPath)],

0 commit comments

Comments
 (0)