Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ded8173
feat: EOD commit, encyption of license key - WIP, need to fix tests
nvyasadobe Apr 17, 2025
c5700bc
feat: fixing failing test
nvyasadobe Apr 21, 2025
8e0ad60
feat: sync branch from spic
nvyasadobe Apr 22, 2025
4baa330
feat: bump alpha version
nvyasadobe Apr 22, 2025
1eb5d39
feat: bumped up beta version
nvyasadobe Apr 24, 2025
3b871b5
feat: modiefied code to address review comment and address for splunk…
nvyasadobe Apr 25, 2025
6de9fd3
feat: very minor correction
nvyasadobe Apr 25, 2025
d3f99b1
feat(metadata): initialize dotenv and include API mesh environment va…
kmaschi Apr 25, 2025
3dd8ea8
Release/5.3.1 (#248) (#249)
kmaschi Apr 28, 2025
7d674da
refactor: removed Newrelic license 40 char restriction
AjazSumaiya Apr 29, 2025
791b99e
Merge branch 'develop' into CEXT-4511
AjazSumaiya Apr 29, 2025
d129e50
bump up package version
AjazSumaiya Apr 29, 2025
bc2ef06
fix: updated keys to enum values
AjazSumaiya Apr 29, 2025
4fdc848
Update package version
AjazSumaiya Apr 30, 2025
6f8b062
Update package version
AjazSumaiya Apr 30, 2025
e2c6cfe
Apply suggestions from code review
AjazSumaiya Apr 30, 2025
355ed70
fix: linting
AjazSumaiya Apr 30, 2025
0dfdce9
Merge pull request #250 from adobe/cext-4578
AjazSumaiya May 5, 2025
e379a25
Merge branch 'develop' into CEXT-4511
AjazSumaiya May 5, 2025
637fd8b
Merge pull request #246 from adobe/CEXT-4511
AjazSumaiya May 6, 2025
c83b160
updated package version
AjazSumaiya May 8, 2025
e3c48e8
Merge branch 'main' into release/5.3.2
kmaschi May 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adobe/aio-cli-plugin-api-mesh",
"version": "5.3.1",
"version": "5.3.2",
"description": "Adobe I/O CLI plugin to develop and manage API mesh sources",
"keywords": [
"oclif-plugin"
Expand Down
56 changes: 44 additions & 12 deletions src/commands/api-mesh/__tests__/set-log-forwarding.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ governing permissions and limitations under the License.
*/

const SetLogForwardingCommand = require('../config/set/log-forwarding');
const crypto = require('crypto');
const {
initSdk,
promptConfirm,
promptSelect,
promptInput,
promptInputSecret,
} = require('../../../helpers');
const { getMeshId, setLogForwarding } = require('../../../lib/smsClient');
const { getMeshId, setLogForwarding, getPublicEncryptionKey } = require('../../../lib/smsClient');

jest.mock('../../../helpers', () => ({
initSdk: jest.fn().mockResolvedValue({}),
Expand All @@ -31,6 +32,21 @@ jest.mock('../../../helpers', () => ({
jest.mock('../../../lib/smsClient');
jest.mock('../../../classes/logger');

jest.mock('crypto');
// Mock randomBytes for aesKey and iv
const mockAesKey = Buffer.from('mockAesKey');
const mockIv = Buffer.from('mockIv');
const mockEncryptedAesKey = Buffer.from('mockEncryptedAesKey');
const mockCipher = {
update: jest.fn().mockReturnValueOnce('mockEncryptedData'),
final: jest.fn().mockReturnValueOnce(''),
};
const mockEncryptedLicenseKey = {
iv: 'bW9ja0l2',
key: 'bW9ja0VuY3J5cHRlZEFlc0tleQ==',
data: 'mockEncryptedData',
};

describe('SetLogForwardingCommand', () => {
let parseSpy;
let logSpy;
Expand Down Expand Up @@ -60,8 +76,13 @@ describe('SetLogForwardingCommand', () => {
workspaceName: 'workspaceName',
});
getMeshId.mockResolvedValue('meshId');
getPublicEncryptionKey.mockResolvedValue('dummy_public_key');
setLogForwarding.mockResolvedValue({ success: true, result: true });
global.requestId = 'dummy_request_id';

// Reset mockCipher methods
mockCipher.update.mockReset().mockReturnValueOnce('mockEncryptedData');
mockCipher.final.mockReset().mockReturnValueOnce('');
});

afterEach(() => {
Expand All @@ -71,6 +92,10 @@ describe('SetLogForwardingCommand', () => {
describe('Test New Relic destination', () => {
/** Success Scenario */
test('sets log forwarding with valid parameters', async () => {
crypto.randomBytes.mockReturnValueOnce(mockAesKey).mockReturnValueOnce(mockIv);
crypto.createCipheriv.mockReturnValueOnce(mockCipher);
crypto.publicEncrypt.mockReturnValueOnce(mockEncryptedAesKey);

const command = new SetLogForwardingCommand([], {});
await command.run();

Expand All @@ -88,7 +113,7 @@ describe('SetLogForwardingCommand', () => {
destination: 'newrelic',
config: {
baseUri: 'https://log-api.newrelic.com/log/v1',
licenseKey: 'abcdef0123456789abcdef0123456789abcdef01',
licenseKey: JSON.stringify(mockEncryptedLicenseKey), // Expect the encrypted value
},
},
);
Expand All @@ -115,15 +140,6 @@ describe('SetLogForwardingCommand', () => {
);
});

test('throws an error if license key has wrong format', async () => {
promptInputSecret.mockResolvedValueOnce('wrongformat'); // Too short

const command = new SetLogForwardingCommand([], {});
await expect(command.run()).rejects.toThrow(
`The license key is in the wrong format. Expected: 40 characters (received: ${11})`,
);
});

test('prompts for missing destination', async () => {
parseSpy.mockResolvedValueOnce({
flags: {
Expand All @@ -135,6 +151,10 @@ describe('SetLogForwardingCommand', () => {
args: [],
});

crypto.randomBytes.mockReturnValueOnce(mockAesKey).mockReturnValueOnce(mockIv);
crypto.createCipheriv.mockReturnValueOnce(mockCipher);
crypto.publicEncrypt.mockReturnValueOnce(mockEncryptedAesKey);

const command = new SetLogForwardingCommand([], {});
await command.run();

Expand Down Expand Up @@ -195,6 +215,10 @@ describe('SetLogForwardingCommand', () => {
args: [],
});

crypto.randomBytes.mockReturnValueOnce(mockAesKey).mockReturnValueOnce(mockIv);
crypto.createCipheriv.mockReturnValueOnce(mockCipher);
crypto.publicEncrypt.mockReturnValueOnce(mockEncryptedAesKey);

const command = new SetLogForwardingCommand([], {});
await command.run();

Expand All @@ -203,6 +227,10 @@ describe('SetLogForwardingCommand', () => {
});

test('sets log forwarding with auto-confirmation', async () => {
crypto.randomBytes.mockReturnValueOnce(mockAesKey).mockReturnValueOnce(mockIv);
crypto.createCipheriv.mockReturnValueOnce(mockCipher);
crypto.publicEncrypt.mockReturnValueOnce(mockEncryptedAesKey);

parseSpy.mockResolvedValueOnce({
flags: {
ignoreCache: false,
Expand All @@ -225,7 +253,7 @@ describe('SetLogForwardingCommand', () => {
destination: 'newrelic',
config: {
baseUri: 'https://log-api.newrelic.com/log/v1',
licenseKey: 'abcdef0123456789abcdef0123456789abcdef01',
licenseKey: JSON.stringify(mockEncryptedLicenseKey), // Expect the encrypted value
},
},
);
Expand All @@ -236,6 +264,10 @@ describe('SetLogForwardingCommand', () => {
const errorMessage = 'Unable to set log forwarding details';
setLogForwarding.mockRejectedValueOnce(new Error(errorMessage));

crypto.randomBytes.mockReturnValueOnce(mockAesKey).mockReturnValueOnce(mockIv);
crypto.createCipheriv.mockReturnValueOnce(mockCipher);
crypto.publicEncrypt.mockReturnValueOnce(mockEncryptedAesKey);

const command = new SetLogForwardingCommand([], {});
await expect(command.run()).rejects.toThrow(
'Failed to set log forwarding details. Try again. RequestId: dummy_request_id',
Expand Down
32 changes: 31 additions & 1 deletion src/commands/api-mesh/config/set/log-forwarding.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ const {
autoConfirmActionFlag,
jsonFlag,
destinations,
LogForwardingKeys,
encryptSecrets,
} = require('../../../../utils');
const { setLogForwarding, getMeshId } = require('../../../../lib/smsClient');
const {
setLogForwarding,
getMeshId,
getPublicEncryptionKey,
} = require('../../../../lib/smsClient');

class SetLogForwardingCommand extends Command {
static flags = {
Expand Down Expand Up @@ -85,6 +91,30 @@ class SetLogForwardingCommand extends Command {

if (shouldContinue) {
try {
// Get publicKey for encryption
const publicKey = await getPublicEncryptionKey(imsOrgCode);
if (!publicKey) {
this.error(
`Unable to set log forwarding details. Unable to get public key. Try again. RequestId: ${global.requestId}`,
);
}
// Get the key to encrypt from config
const getEncryptableKey = config => {
if (LogForwardingKeys.LICENSE_KEY in config) return LogForwardingKeys.LICENSE_KEY;
if (LogForwardingKeys.HEC_TOKEN in config) return LogForwardingKeys.HEC_TOKEN;
return null;
};
const keyToEncrypt = getEncryptableKey(destinationConfig.config);
if (!keyToEncrypt) {
this.error(
`Unable to set log forwarding details. No valid key to encrypt found in the configuration. Try again. RequestId: ${global.requestId}`,
);
}
// Encrypt the key
destinationConfig.config[keyToEncrypt] = await encryptSecrets(
publicKey,
destinationConfig.config[keyToEncrypt],
);
const response = await setLogForwarding(
imsOrgCode,
projectId,
Expand Down
13 changes: 7 additions & 6 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ const logFilenameFlag = Flags.string({
required: true,
});

const LogForwardingKeys = {
LICENSE_KEY: 'licenseKey',
HEC_TOKEN: 'hecToken',
};

// The `destinations` object to hold the configuration for log forwarding destinations.
// It prompts for the required inputs for the destination.
// Each destination can have different key/value pairs of configuration credentials.
Expand Down Expand Up @@ -132,11 +137,6 @@ const destinations = {
if (!value) {
throw new Error('License key is required');
}
if (value.length !== 40) {
throw new Error(
`The license key is in the wrong format. Expected: 40 characters (received: ${value.length})`,
);
}
},
},
],
Expand Down Expand Up @@ -777,7 +777,7 @@ async function localToUTCTime(timeString) {
try {
//Get the local timezone
// takes the timezone where the javascript runtime is running
// reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions#browser_compatibility:~:text=The%20value%20provided%20for%20this%20property%20in%20the%20options%20argument%2C%20with%20default%20filled%20in%20as%20needed.%20It%20is%20an%20IANA%20time%20zone%20name.%20The%20default%20is%20the%20runtime%27s%20default%20time%20zone.
// reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions#browser_compatibility:~:text=The%20value%20provided%20for%20this%20property%20in%20the%20options%20argument%2C%20with%20default%20filled%20in%20as%20needed.%20It%20is%20an%20IANA%20time%20zone.%20The%20default%20is%20the%20runtime%27s%20default%20time%20zone.
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

// Create a Date object from the formatted time string
Expand Down Expand Up @@ -824,4 +824,5 @@ module.exports = {
localToUTCTime,
cachePurgeAllActionFlag,
destinations,
LogForwardingKeys,
};
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8208,7 +8208,7 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==

ms@^2.1.1, ms@^2.1.3:
ms@^2.1.1:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
Expand Down
Loading