Skip to content

Commit 0b943fd

Browse files
cs-rajclaude
andcommitted
fix(audit): honour skipConfirm in workflow and extension removal
Import runs audit fix with skipConfirm in --external-config instead of passing --yes. Every other audit confirmation honours skipConfirm and copy-dir, but the per-item removal prompts for workflows and extensions only checked --yes, so `cm:stacks:import --yes` still stopped once for each workflow or extension whose content types were all missing. Accept copy-dir, skipConfirm or yes there, matching the file-write confirmation in the same modules. Also upgrade adm-zip to 0.6.1 in apps-cli and moment to 2.31.0 in content-type to clear high-severity Snyk findings, and bump @contentstack/cli-launch and the uuid, brace-expansion, js-yaml, fast-uri and ws overrides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent bb2edc2 commit 0b943fd

9 files changed

Lines changed: 219 additions & 79 deletions

File tree

‎.talismanrc‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
fileignoreconfig:
22

33
- filename: pnpm-lock.yaml
4-
checksum: 90ca97ef1a06fb5b7d8071f1317e079de6a34fce91559f70f80d9d958b5a834e
4+
checksum: 8ab0fa4a3ef73e44c440757223202629b999f011c617888c4e7d4f3c90f546d8
55
version: '1.0'
6+
- filename: packages/contentstack-audit/test/unit/modules/extensions.test.ts
7+
checksum: 548b6e10241eb38df4b92f2dec90987b555ed6b7c582846d539828854eb1dadc

‎packages/contentstack-apps-cli/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
"dependencies": {
2424
"@apollo/client": "^3.14.1",
2525
"@contentstack/cli-command": "~1.8.7",
26-
"@contentstack/cli-launch": "^1.11.1",
26+
"@contentstack/cli-launch": "^1.11.3",
2727
"@contentstack/cli-utilities": "~1.19.2",
28-
"adm-zip": "^0.6.0",
28+
"adm-zip": "^0.6.1",
2929
"chalk": "^4.1.2",
3030
"lodash": "^4.18.1",
3131
"shelljs": "^0.10.0",

‎packages/contentstack-audit/src/modules/extensions.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,11 @@ export default class Extensions {
167167
} else {
168168
log.debug(`Extension ${title} has no valid content types or scope not found`, this.config.auditContext);
169169
cliux.print($t(commonMsg.EXTENSION_FIX_WARN, { title: title, uid }), { color: 'yellow' });
170-
const shouldDelete = this.config.flags.yes || (await cliux.confirm(commonMsg.EXTENSION_FIX_CONFIRMATION));
170+
const shouldDelete =
171+
this.config.flags['copy-dir'] ||
172+
this.config.flags['external-config']?.skipConfirm ||
173+
this.config.flags.yes ||
174+
(await cliux.confirm(commonMsg.EXTENSION_FIX_CONFIRMATION));
171175
if (shouldDelete) {
172176
log.debug(`Deleting extension: ${title} (${uid})`, this.config.auditContext);
173177
delete newExtensionSchema[uid];

‎packages/contentstack-audit/src/modules/workflows.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,12 @@ export default class Workflows {
223223

224224
cliux.print(warningMessage, { color: 'yellow' });
225225

226-
if (this.config.flags.yes || (await cliux.confirm(commonMsg.WORKFLOW_FIX_CONFIRMATION))) {
226+
if (
227+
this.config.flags['copy-dir'] ||
228+
this.config.flags['external-config']?.skipConfirm ||
229+
this.config.flags.yes ||
230+
(await cliux.confirm(commonMsg.WORKFLOW_FIX_CONFIRMATION))
231+
) {
227232
log.debug(`Deleting workflow ${name} (${uid})`, this.config.auditContext);
228233
delete newWorkflowSchema[workflow.uid];
229234
} else {

‎packages/contentstack-audit/test/unit/modules/extensions.test.ts‎

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ux, cliux } from '@contentstack/cli-utilities';
66

77
import config from '../../../src/config';
88
import { Extensions } from '../../../src/modules';
9-
import { $t, auditMsg } from '../../../src/messages';
9+
import { $t, auditMsg, commonMsg } from '../../../src/messages';
1010
import sinon from 'sinon';
1111
import { Extension } from '../../../src/types';
1212
import { mockLogger } from '../mock-logger';
@@ -387,4 +387,67 @@ describe('Extensions scope containing content_types uids', () => {
387387
},
388388
);
389389
});
390+
391+
describe('fixExtensionsScope confirmation before removing an extension', () => {
392+
class ExtensionsWithCapturedFix extends Extensions {
393+
public fixedExtensions: Record<string, Extension> = {};
394+
395+
async writeFixContent(fixedExtensions: Record<string, Extension>) {
396+
this.fixedExtensions = fixedExtensions;
397+
}
398+
}
399+
400+
// ext1 and ext2 are scoped only to missing content types, so the fix removes them.
401+
const createExtensions = (flags: Record<string, unknown>) =>
402+
new ExtensionsWithCapturedFix({
403+
moduleName: 'extensions',
404+
ctSchema: cloneDeep(require('./../mock/contents/extensions/ctSchema.json')),
405+
config: Object.assign(cloneDeep(config), {
406+
basePath: resolve(`./test/unit/mock/contents/extensions/invalidExtensions/`),
407+
flags,
408+
}),
409+
fix: true,
410+
});
411+
412+
it('should remove the extensions without prompting when external-config skipConfirm is set', async () => {
413+
const confirm = sinon.stub(cliux, 'confirm').resolves(false);
414+
const ext = createExtensions({ 'external-config': { skipConfirm: true } });
415+
416+
await ext.run();
417+
418+
expect(confirm.notCalled).to.be.true;
419+
expect(ext.fixedExtensions).to.not.have.any.keys('ext1', 'ext2');
420+
});
421+
422+
it('should remove the extensions without prompting when copy-dir is set', async () => {
423+
const confirm = sinon.stub(cliux, 'confirm').resolves(false);
424+
const ext = createExtensions({ 'copy-dir': true });
425+
426+
await ext.run();
427+
428+
expect(confirm.notCalled).to.be.true;
429+
expect(ext.fixedExtensions).to.not.have.any.keys('ext1', 'ext2');
430+
});
431+
432+
it('should remove the extensions without prompting when yes is set', async () => {
433+
const confirm = sinon.stub(cliux, 'confirm').resolves(false);
434+
const ext = createExtensions({ yes: true });
435+
436+
await ext.run();
437+
438+
expect(confirm.notCalled).to.be.true;
439+
expect(ext.fixedExtensions).to.not.have.any.keys('ext1', 'ext2');
440+
});
441+
442+
it('should ask once per extension to remove and keep them when the user declines', async () => {
443+
const confirm = sinon.stub(cliux, 'confirm').resolves(false);
444+
const ext = createExtensions({});
445+
446+
await ext.run();
447+
448+
expect(confirm.callCount).to.equal(2);
449+
expect(confirm.alwaysCalledWithExactly(commonMsg.EXTENSION_FIX_CONFIRMATION)).to.be.true;
450+
expect(ext.fixedExtensions).to.include.all.keys('ext1', 'ext2');
451+
});
452+
});
390453
});

‎packages/contentstack-audit/test/unit/modules/workflow.test.ts‎

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { resolve } from 'path';
33
import { fancy } from 'fancy-test';
44
import { expect } from 'chai';
55
import cloneDeep from 'lodash/cloneDeep';
6-
import { ux } from '@contentstack/cli-utilities';
6+
import { ux, cliux } from '@contentstack/cli-utilities';
77
import sinon from 'sinon';
88

99
import config from '../../../src/config';
1010
import { Workflows } from '../../../src/modules';
11-
import { $t, auditMsg } from '../../../src/messages';
11+
import { $t, auditMsg, commonMsg } from '../../../src/messages';
12+
import { Workflow } from '../../../src/types';
1213
import { values } from 'lodash';
1314
import { mockLogger } from '../mock-logger';
1415

@@ -147,4 +148,69 @@ describe('Workflows', () => {
147148
]);
148149
});
149150
});
151+
152+
describe('fixWorkflowSchema confirmation before removing a workflow', () => {
153+
class WorkflowsWithCapturedFix extends Workflows {
154+
public fixedWorkflows: Record<string, Workflow> = {};
155+
156+
async writeFixContent(newWorkflowSchema: Record<string, Workflow>) {
157+
this.fixedWorkflows = newWorkflowSchema;
158+
}
159+
}
160+
161+
const createWorkflows = (flags: Record<string, unknown>) =>
162+
new WorkflowsWithCapturedFix({
163+
moduleName: 'workflows',
164+
// Without ct2, every content type on wf3 is missing, so the fix removes wf3.
165+
ctSchema: cloneDeep(require('./../mock/contents/workflows/ctSchema.json')).filter(
166+
(ct: { uid: string }) => ct.uid !== 'ct2',
167+
),
168+
config: Object.assign(cloneDeep(config), {
169+
basePath: resolve(`./test/unit/mock/contents/`),
170+
branch: undefined,
171+
flags,
172+
}),
173+
fix: true,
174+
});
175+
176+
it('should remove the workflow without prompting when external-config skipConfirm is set', async () => {
177+
const confirm = sinon.stub(cliux, 'confirm').resolves(false);
178+
const wf = createWorkflows({ 'external-config': { skipConfirm: true } });
179+
180+
await wf.run();
181+
182+
expect(confirm.notCalled).to.be.true;
183+
expect(wf.fixedWorkflows).to.not.have.property('wf3');
184+
});
185+
186+
it('should remove the workflow without prompting when copy-dir is set', async () => {
187+
const confirm = sinon.stub(cliux, 'confirm').resolves(false);
188+
const wf = createWorkflows({ 'copy-dir': true });
189+
190+
await wf.run();
191+
192+
expect(confirm.notCalled).to.be.true;
193+
expect(wf.fixedWorkflows).to.not.have.property('wf3');
194+
});
195+
196+
it('should remove the workflow without prompting when yes is set', async () => {
197+
const confirm = sinon.stub(cliux, 'confirm').resolves(false);
198+
const wf = createWorkflows({ yes: true });
199+
200+
await wf.run();
201+
202+
expect(confirm.notCalled).to.be.true;
203+
expect(wf.fixedWorkflows).to.not.have.property('wf3');
204+
});
205+
206+
it('should ask once per workflow to remove and keep it when the user declines', async () => {
207+
const confirm = sinon.stub(cliux, 'confirm').resolves(false);
208+
const wf = createWorkflows({});
209+
210+
await wf.run();
211+
212+
expect(confirm.calledOnceWithExactly(commonMsg.WORKFLOW_FIX_CONFIRMATION)).to.be.true;
213+
expect(wf.fixedWorkflows).to.have.property('wf3');
214+
});
215+
});
150216
});

‎packages/contentstack-content-type/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"cli-ux": "^6.0.9",
1212
"diff": "^9.0.0",
1313
"diff2html": "^3.4.56",
14-
"moment": "^2.30.1",
14+
"moment": "^2.31.0",
1515
"node-graphviz": "^0.1.1",
1616
"table": "^6.9.0",
1717
"tmp": "^0.2.7",

0 commit comments

Comments
 (0)