Skip to content
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.6.0",
"version": "5.6.1",
"description": "Adobe I/O CLI plugin to develop and manage API mesh sources",
"keywords": [
"oclif-plugin"
Expand Down
8 changes: 8 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const dotenv = require('dotenv');
dotenv.config();
const clientEnv = getCliEnv();

const MAX_SECRET_SIZE_BYTES = 5 * 1024; // 5 KB — matches Cloudflare's per-secret limit

const StageConstants = {
DEV_CONSOLE_BASE_URL: 'https://developers-stage.adobe.io/console',
DEV_CONSOLE_API_KEY: 'adobe-api-manager-sms-stage',
Expand All @@ -12,6 +14,8 @@ const StageConstants = {
SMS_BASE_URL: 'https://graph-stage.adobe.io/api-admin',
MESH_BASE_URL: 'https://edge-stage-graph.adobe.io/api',
SMS_API_KEY: 'adobe-graph-stage-onboarding',
MAX_SECRET_COUNT: 50,
MAX_SECRET_SIZE_BYTES,
};

const ProdConstants = {
Expand All @@ -23,6 +27,8 @@ const ProdConstants = {
MESH_BASE_URL: 'https://edge-graph.adobe.io/api',
MESH_SANDBOX_BASE_URL: 'https://edge-sandbox-graph.adobe.io/api',
SMS_API_KEY: 'adobe-graph-prod',
MAX_SECRET_COUNT: 50,
MAX_SECRET_SIZE_BYTES,
};

const envConstants = clientEnv === 'stage' ? StageConstants : ProdConstants;
Expand All @@ -38,4 +44,6 @@ module.exports = {
MESH_BASE_URL: process.env.MESH_BASE_URL || envConstants.MESH_BASE_URL,
MESH_SANDBOX_BASE_URL: process.env.MESH_SANDBOX_BASE_URL || envConstants.MESH_SANDBOX_BASE_URL,
SMS_API_KEY: process.env.SMS_API_KEY || envConstants.SMS_API_KEY,
MAX_SECRET_COUNT: process.env.MAX_SECRET_COUNT || envConstants.MAX_SECRET_COUNT,
MAX_SECRET_SIZE_BYTES: process.env.MAX_SECRET_SIZE_BYTES || envConstants.MAX_SECRET_SIZE_BYTES,
};
38 changes: 38 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const parseEnv = require('envsub/js/envsub-parser');
const os = require('os');
const chalk = require('chalk');
const crypto = require('crypto');
const CONSTANTS = require('./constants');

const { MAX_SECRET_COUNT, MAX_SECRET_SIZE_BYTES } = CONSTANTS;

/**
* @returns returns the root directory of the project
Expand Down Expand Up @@ -513,6 +516,27 @@ async function interpolateSecrets(secretsFilePath, command) {
}
}

/**
* Validates that each individual secret value does not exceed MAX_SECRET_SIZE_BYTES
* (5 KB — Cloudflare's per-secret limit).
* the YAML serialization of that value is used for the size measurement.
*
* @param {object} parsedSecrets Parsed secrets object from YAML
*/
function validateSecretsSize(parsedSecrets) {
for (const [key, value] of Object.entries(parsedSecrets)) {
const valueString = typeof value === 'string' ? value : YAML.stringify(value);
const valueSizeBytes = Buffer.byteLength(valueString, 'utf8');
if (valueSizeBytes > MAX_SECRET_SIZE_BYTES) {
throw new Error(
chalk.red(
`Secret "${key}" exceeds the 5 KB size limit. Please reduce its size and try again.`,
),
);
}
}
}

/**
* Parse secrets YAML content.
*
Expand Down Expand Up @@ -544,7 +568,21 @@ async function parseSecrets(secretsContent) {
if (typeof parsedSecrets === 'string') {
throw new Error(chalk.red('Please provide a valid YAML in key:value format.'));
}

const numSecrets = Object.entries(parsedSecrets).length;

if (numSecrets > MAX_SECRET_COUNT) {
throw new Error(
chalk.red(
`Number of secrets exceeds limit. Maximum allowed number of secrets is ${MAX_SECRET_COUNT}`,
),
);
}

validateSecretsSize(parsedSecrets);

const secretsYamlString = YAML.stringify(parsedSecrets);

return secretsYamlString; //TODO: here we will encrypt secrets and return.
} catch (err) {
throw new Error(chalk.red(getSecretsYamlParseError(err)));
Expand Down
Loading