From 07a0d4cd8dc15f003144380b2614df25934027ee Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Wed, 16 Jul 2025 22:54:19 -0700 Subject: [PATCH] Fixes GitOps route API environment status update --- npm-shrinkwrap.json | 68 +++++++++++++++++------------ package.json | 6 +-- sonar-project.properties | 2 +- src/api-docs/swagger-info.js | 2 +- src/services/gitops/push-changed.js | 10 ++++- tests/gitops.test.js | 64 +++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 35 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index b74d974..2f8ffff 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "switcher-api", - "version": "1.4.0", + "version": "1.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "switcher-api", - "version": "1.4.0", + "version": "1.4.1", "license": "MIT", "dependencies": { "axios": "^1.10.0", @@ -14,7 +14,7 @@ "cors": "^2.8.5", "express": "^5.1.0", "express-basic-auth": "^1.2.1", - "express-rate-limit": "^7.5.1", + "express-rate-limit": "^8.0.1", "express-validator": "^7.2.1", "graphql": "^16.11.0", "graphql-http": "^1.22.4", @@ -23,7 +23,7 @@ "jsonwebtoken": "^9.0.2", "moment": "^2.30.1", "mongodb": "^6.17.0", - "mongoose": "^8.16.3", + "mongoose": "^8.16.4", "pino": "^9.7.0", "pino-pretty": "^13.0.0", "swagger-ui-express": "^5.0.1", @@ -1385,9 +1385,9 @@ "license": "Apache-2.0" }, "node_modules/@sinclair/typebox": { - "version": "0.34.37", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz", - "integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==", + "version": "0.34.38", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.38.tgz", + "integrity": "sha512-HpkxMmc2XmZKhvaKIZZThlHmx1L0I/V1hWK1NubtlFnr6ZqdiOpV72TKudZUNQjZNsyDBay72qFEhEvb+bcwcA==", "dev": true, "license": "MIT" }, @@ -1531,9 +1531,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.0.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz", - "integrity": "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ==", + "version": "24.0.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.14.tgz", + "integrity": "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==", "dev": true, "license": "MIT", "dependencies": { @@ -2814,9 +2814,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.182", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz", - "integrity": "sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA==", + "version": "1.5.186", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.186.tgz", + "integrity": "sha512-lur7L4BFklgepaJxj4DqPk7vKbTEl0pajNlg2QjE5shefmlmBLm2HvQ7PMf1R/GvlevT/581cop33/quQcfX3A==", "dev": true, "license": "ISC" }, @@ -3248,10 +3248,13 @@ } }, "node_modules/express-rate-limit": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", - "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.0.1.tgz", + "integrity": "sha512-aZVCnybn7TVmxO4BtlmnvX+nuz8qHW124KKJ8dumsBsmv5ZLxE0pYu7S2nwyRBGHHCAzdmnGyrc5U/rksSPO7Q==", "license": "MIT", + "dependencies": { + "ip-address": "10.0.1" + }, "engines": { "node": ">= 16" }, @@ -3455,9 +3458,9 @@ } }, "node_modules/form-data": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", - "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -3976,6 +3979,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4736,9 +4748,9 @@ } }, "node_modules/jest-util/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -5357,9 +5369,9 @@ } }, "node_modules/mongoose": { - "version": "8.16.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.16.3.tgz", - "integrity": "sha512-p2JOsRQG7j0vXhLpsWw5Slm2VnDeJK8sRyqSyegk5jQujuP9BTOZ1Di9VX/0lYfBhZ2DpAExi51QTd4pIqSgig==", + "version": "8.16.4", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.16.4.tgz", + "integrity": "sha512-jslgdQ8pY2vcNSKPv3Dbi5ogo/NT8zcvf6kPDyD8Sdsjsa1at3AFAF0F5PT+jySPGSPbvlNaQ49nT9h+Kx2UDA==", "license": "MIT", "dependencies": { "bson": "^6.10.4", @@ -6792,9 +6804,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.26.2", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.26.2.tgz", - "integrity": "sha512-WmMS9iMlHQejNm/Uw5ZTo4e3M2QMmEavRz7WLWVsq7Mlx4PSHJbY+VCrLsAz9wLxyHVgrJdt7N8+SdQLa52Ykg==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.27.0.tgz", + "integrity": "sha512-tS6LRyBhY6yAqxrfsA9IYpGWPUJOri6sclySa7TdC7XQfGLvTwDY531KLgfQwHEtQsn+sT4JlUspbeQDBVGWig==", "license": "Apache-2.0", "dependencies": { "@scarf/scarf": "=1.4.0" diff --git a/package.json b/package.json index 153519f..2e2682d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "switcher-api", - "version": "1.4.0", + "version": "1.4.1", "description": "Feature Flag/Toggle API", "main": "src/start.js", "type": "module", @@ -41,7 +41,7 @@ "cors": "^2.8.5", "express": "^5.1.0", "express-basic-auth": "^1.2.1", - "express-rate-limit": "^7.5.1", + "express-rate-limit": "^8.0.1", "express-validator": "^7.2.1", "graphql": "^16.11.0", "graphql-http": "^1.22.4", @@ -50,7 +50,7 @@ "jsonwebtoken": "^9.0.2", "moment": "^2.30.1", "mongodb": "^6.17.0", - "mongoose": "^8.16.3", + "mongoose": "^8.16.4", "pino": "^9.7.0", "pino-pretty": "^13.0.0", "swagger-ui-express": "^5.0.1", diff --git a/sonar-project.properties b/sonar-project.properties index 9cdcc3e..8c7dc45 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,7 +1,7 @@ sonar.projectKey=switcherapi_switcher-api sonar.projectName=switcher-api sonar.organization=switcherapi -sonar.projectVersion=1.4.0 +sonar.projectVersion=1.4.1 sonar.links.homepage=https://github.com/switcherapi/switcher-api sonar.testExecutionReportPaths=test-report.xml diff --git a/src/api-docs/swagger-info.js b/src/api-docs/swagger-info.js index c99233b..d15bfc5 100644 --- a/src/api-docs/swagger-info.js +++ b/src/api-docs/swagger-info.js @@ -1,6 +1,6 @@ export default { title: 'Switcher API', - version: 'v1.4.0', + version: 'v1.4.1', description: 'Switcher API is a Feature Flag API focused on toggling features over different environments and applications.', contact: { name: 'Roger Floriano (petruki)', diff --git a/src/services/gitops/push-changed.js b/src/services/gitops/push-changed.js index 1bc7575..f0b4370 100644 --- a/src/services/gitops/push-changed.js +++ b/src/services/gitops/push-changed.js @@ -17,10 +17,13 @@ async function processChangedGroup(domain, change, environment) { const admin = { _id: domain.owner, email: ADMIN_EMAIL }; const content = change.content; const group = await getGroupConfig({ domain: domain._id, name: change.path[0] }); + + const updatedActivated = new Map(group.activated); + updatedActivated.set(environment, getChangedValue(content.activated, group.activated.get(environment))); await updateGroup(group._id, { description: getChangedValue(content.description, group.description), - activated: new Map().set(environment, getChangedValue(content.activated, group.activated.get(environment))) + activated: updatedActivated }, admin); } @@ -29,9 +32,12 @@ async function processChangedConfig(domain, change, environment) { const admin = { _id: domain.owner, email: ADMIN_EMAIL }; const config = await getConfig({ domain: domain._id, key: change.path[1] }); + const updatedActivated = new Map(config.activated); + updatedActivated.set(environment, getChangedValue(content.activated, config.activated.get(environment))); + await updateConfig(config._id, { description: getChangedValue(content.description, config.description), - activated: new Map().set(environment, getChangedValue(content.activated, config.activated.get(environment))) + activated: updatedActivated }, admin); if (content.relay) { diff --git a/tests/gitops.test.js b/tests/gitops.test.js index 0f268fb..c7ec94c 100644 --- a/tests/gitops.test.js +++ b/tests/gitops.test.js @@ -429,6 +429,38 @@ describe('GitOps - Push Changed', () => { expect(group.description).toBe('Changed Group Description'); }); + test('GITOPS_SUITE - Should push changes - Changed Group while keeping default', async () => { + const token = generateToken('30s'); + + const lastUpdate = Date.now(); + const req = await request(app) + .post('/gitops/v1/push') + .set('Authorization', `Bearer ${token}`) + .send({ + environment: 'staging', + changes: [{ + action: 'CHANGED', + diff: 'GROUP', + path: ['Group Test'], + content: { + activated: true, + description: 'Changed Group Description' + } + }] + }) + .expect(200); + + expect(req.body.message).toBe('Changes applied successfully'); + expect(req.body.version).toBeGreaterThan(lastUpdate); + + // Check if the changes were applied + const group = await GroupConfig.findOne({ name: 'Group Test', domain: domainId }).lean().exec(); + expect(group).not.toBeNull(); + expect(group.activated['staging']).toBe(true); + expect(group.activated[EnvType.DEFAULT]).toBeDefined(); + expect(group.description).toBe('Changed Group Description'); + }); + test('GITOPS_SUITE - Should push changes - Changed Switcher', async () => { const token = generateToken('30s'); @@ -460,6 +492,38 @@ describe('GitOps - Push Changed', () => { expect(config.description).toBe('Changed Switcher Description'); }); + test('GITOPS_SUITE - Should push changes - Changed Switcher while keeping default', async () => { + const token = generateToken('30s'); + + const lastUpdate = Date.now(); + const req = await request(app) + .post('/gitops/v1/push') + .set('Authorization', `Bearer ${token}`) + .send({ + environment: 'staging', + changes: [{ + action: 'CHANGED', + diff: 'CONFIG', + path: ['Group Test', 'TEST_CONFIG_KEY'], + content: { + activated: true, + description: 'Changed Switcher Description' + } + }] + }) + .expect(200); + + expect(req.body.message).toBe('Changes applied successfully'); + expect(req.body.version).toBeGreaterThan(lastUpdate); + + // Check if the changes were applied + const config = await Config.findOne({ key: 'TEST_CONFIG_KEY', domain: domainId }).lean().exec(); + expect(config).not.toBeNull(); + expect(config.activated['staging']).toBe(true); + expect(config.activated[EnvType.DEFAULT]).toBeDefined(); + expect(config.description).toBe('Changed Switcher Description'); + }); + test('GITOPS_SUITE - Should push changes - Changed Switcher Relay (added)', async () => { const token = generateToken('30s');