From 1c0ddbad342e21d23e898133706fa7e9fcb738fc Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Sun, 1 Nov 2026 12:04:52 +0800 Subject: [PATCH 1/2] Include restricted API Keys in typed discovery and audit references --- COMPATIBILITY.md | 7 ++ README.md | 7 ++ app/utils/ai-command-contract.js | 4 +- app/utils/ai-resource-registry.js | 4 +- bridge/package-lock.json | 4 +- bridge/package.json | 2 +- bridge/server.mjs | 2 +- ...ass-replacement.node24-ignore-scripts.json | 4 +- docs/releases/web-console-1.6.203.md | 22 ++++++ package-lock.json | 4 +- package.json | 2 +- scripts/check-modernization-blockers | 4 +- scripts/package-webmcp-bridge.py | 2 +- scripts/test-webmcp-audit.mjs | 79 +++++++++++++++++++ 14 files changed, 132 insertions(+), 15 deletions(-) create mode 100644 docs/releases/web-console-1.6.203.md diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 6930698cd9..4e5fbc9a8b 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -1,5 +1,12 @@ # Compatibility Contract +## Candidate 1.6.203 / bridge 0.2.5 + +Adds restricted-Key discovery against the existing Engine361 typed contract. +Default discovery remains ordinary `apiKey`; use `apiKeyRestricted` explicitly. +The assembled Server also needs Engine362 for the separately verified native +ServiceIndex cleanup repair. Publication and runtime acceptance remain pending. + ## Web Console 1.6.202 / bridge 0.2.4 published The matching typed workflows require Engine 0.183.361 and the installed audit diff --git a/README.md b/README.md index f743a5ded8..3c929aa527 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,13 @@ Rancher 1.6 ecosystem. It is not affiliated with Rancher Labs or SUSE. This fork of [`rancher/ui`](https://github.com/rancher/ui) preserves upstream history, authorship, licenses, and dependency notices. +## In development: 1.6.203 / bridge 0.2.5 + +Restricted API Keys gain the same name-based discovery and audit-reference flow +as ordinary Keys. Select `apiKeyRestricted` explicitly; the default searches +`apiKey` only. This is partial family coverage, not a merged search or complete +frontend automation. Publication and designated QA acceptance remain pending. + ## Current component [Web Console **1.6.202** / bridge **0.2.4**](https://github.com/PastureStack/web-console/releases/tag/1.6.202) diff --git a/app/utils/ai-command-contract.js b/app/utils/ai-command-contract.js index e6ee2ed787..4e235999df 100644 --- a/app/utils/ai-command-contract.js +++ b/app/utils/ai-command-contract.js @@ -12,7 +12,7 @@ const catalogAnswers = {type: 'array', maxItems: 100, items: schema({questionRef value: {type: ['string', 'number', 'boolean'], minLength: 0, maxLength: 4096, minimum: -Number.MAX_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER}, resourceRef: string('An authorized resourceRef, or a same-session serviceRef for service questions. Never send a raw resource ID.')}, ['questionRef']), description: 'Typed answers only. Each questionRef accepts exactly one value or resourceRef. For an optional reference, value "" explicitly selects no resource. Human-only inputs must be completed in the console; never send a password or secret value.'}; const auditFilters = schema({ - keyRef: string('Optional API Key resourceRef returned by find_resources; never supply a raw credential ID.'), + keyRef: string('Optional apiKey or apiKeyRestricted resourceRef returned by find_resources in api-keys with the intended resourceType; never supply a raw credential ID.'), environmentRef: string('Optional visible project resourceRef; current environment is used by default.'), environmentScope: {...string('Use current by default. all-visible explicitly requests only environments allowed by the native audit owner.'), enum: ['current', 'all-visible']}, from: string('Range start, inclusive, RFC3339 with timezone; supply together with to.', 64), @@ -28,7 +28,7 @@ const auditFilters = schema({ }); export const COMMANDS = Object.freeze([ {name: 'list_capabilities', description: 'List the closed resource families, their implementation coverage and current read availability. Pending adapters are not implemented. Does not change environment or expose credentials.', inputSchema: schema({})}, - {name: 'find_resources', description: 'Find visible resource metadata in a named family. resourceType defaults to the first type listed by list_capabilities. Return all same-name candidates; never select the first automatically. In catalog, find catalogTemplate by name first, then list catalogTemplateVersion with its resourceRef as parentRef and no query. Version metadata does not establish compatibility. Parent and cursor references must be reused unchanged.', + {name: 'find_resources', description: 'Find visible resource metadata in a named family. resourceType defaults to the first type listed by list_capabilities. In api-keys, select apiKey for legacy Keys or apiKeyRestricted for restricted or expiring Keys; the default searches apiKey only, without combining kinds. Return all same-name candidates within the selected type; never select the first automatically. In catalog, find catalogTemplate by name first, then list catalogTemplateVersion with its resourceRef as parentRef and no query. Version metadata does not establish compatibility. Parent and cursor references must be reused unchanged.', inputSchema: schema({family: {...string('Family from list_capabilities.'), enum: RESOURCE_FAMILIES.map((item) => item.name)}, resourceType: {...string('Optional type within that family, from list_capabilities.'), enum: RESOURCE_TYPES}, query: string('Optional resource name words.'), parentRef: string('Optional resourceRef of the parent type listed by list_capabilities.'), diff --git a/app/utils/ai-resource-registry.js b/app/utils/ai-resource-registry.js index 01de8a8c71..74db8054c8 100644 --- a/app/utils/ai-resource-registry.js +++ b/app/utils/ai-resource-registry.js @@ -24,7 +24,9 @@ const family = (name, resources, coverageStatus = 'implemented', reason = '') => export const RESOURCE_FAMILIES = Object.freeze([ family('accounts', [global('account', 'accounts', ['kind'])]), - family('api-keys', [global('apiKey', 'apikeys', ['kind', 'expiresAt'])]), + family('api-keys', [global('apiKey', 'apikeys', ['kind', 'expiresAt']), + global('apiKeyRestricted', 'apikeyrestricteds', ['kind', 'expiresAt'])], 'pending-adapter', + 'Safe metadata reads support legacy apiKey and restricted or expiring apiKeyRestricted. Select resourceType explicitly for the intended kind, including same-name Keys. Omitting resourceType queries apiKey only and does not combine both kinds. Credential creation, policy changes and revocation remain in the normal human Key UI; this is partial workflow coverage.'), family('audit', [global('auditLog', 'auditLogs', ['eventType', 'resourceType', 'responseCode', 'httpStatus', 'authType', 'interactionChannel', 'decision', 'outcome', 'operation'])], 'pending-adapter', 'Typed audit metadata queries are implemented through the matching Engine and broker owner for the native session and dedicated-Key bridge. Export and raw request/response payloads remain in the human audit UI; this is partial workflow coverage.'), family('authentication', [], 'pending-adapter', 'Authentication configuration uses its dedicated authenticated API. Login and credential entry remain human ceremonies.'), family('catalog', [catalog('catalogTemplate', ['name', 'description', 'catalogId', 'templateBase', 'templateKey', 'catalogScope', 'defaultVersion', 'maintainer', 'license']), diff --git a/bridge/package-lock.json b/bridge/package-lock.json index 196dd0c412..fcfc4c0af6 100644 --- a/bridge/package-lock.json +++ b/bridge/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pasturestack/webmcp-bridge", - "version": "0.2.4", + "version": "0.2.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pasturestack/webmcp-bridge", - "version": "0.2.4", + "version": "0.2.5", "dependencies": { "@modelcontextprotocol/sdk": "1.32.2" }, diff --git a/bridge/package.json b/bridge/package.json index 0440c56139..cc9ee041b9 100644 --- a/bridge/package.json +++ b/bridge/package.json @@ -1,6 +1,6 @@ { "name": "@pasturestack/webmcp-bridge", - "version": "0.2.4", + "version": "0.2.5", "private": true, "type": "module", "description": "Isolated stdio adapter for the shared PastureStack command contract", diff --git a/bridge/server.mjs b/bridge/server.mjs index b593915429..9ea05b0469 100644 --- a/bridge/server.mjs +++ b/bridge/server.mjs @@ -7,7 +7,7 @@ try { const path = process.env.PASTURESTACK_BRIDGE_CONFIG; if (!path) throw new SetupError('CONFIG_REQUIRED'); const bridge = await createBridge(await loadConfig(path)); - const server = new Server({name: 'pasturestack-webmcp-bridge', version: '0.2.4'}, { + const server = new Server({name: 'pasturestack-webmcp-bridge', version: '0.2.5'}, { capabilities: {tools: {}}, instructions: 'Use names and returned opaque references. Never guess IDs. A human must approve change plans in the console. Rejected calls must be repaired only as directed; never evade permissions. Accepted/running is not success. Read the existing operation until verifiedResult=true.', }); diff --git a/docs/baselines/npm-package-lock.sass-replacement.node24-ignore-scripts.json b/docs/baselines/npm-package-lock.sass-replacement.node24-ignore-scripts.json index 7953b7ab84..a57ddc9b2a 100644 --- a/docs/baselines/npm-package-lock.sass-replacement.node24-ignore-scripts.json +++ b/docs/baselines/npm-package-lock.sass-replacement.node24-ignore-scripts.json @@ -1,12 +1,12 @@ { "name": "@pasturestack/web-console", - "version": "1.6.202", + "version": "1.6.203", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pasturestack/web-console", - "version": "1.6.202", + "version": "1.6.203", "license": "Apache-2.0", "dependencies": { "sass": "1.103.1" diff --git a/docs/releases/web-console-1.6.203.md b/docs/releases/web-console-1.6.203.md new file mode 100644 index 0000000000..c00e80b822 --- /dev/null +++ b/docs/releases/web-console-1.6.203.md @@ -0,0 +1,22 @@ +# Web Console 1.6.203 / bridge 0.2.5 + +Source candidate; publication and designated workflow acceptance remain pending. + +The shared API Key resource family now includes `apiKeyRestricted`. Both browser +WebMCP and the stdio bridge can find a restricted Key by its visible name, use +the returned opaque reference and query its authorized audit metadata. The Engine +already supports this native type; no credential manager or policy is widened. + +The family remains partial. Omitting `resourceType` searches ordinary `apiKey` +resources; choose `apiKeyRestricted` for restricted Keys. The two collections are +not silently merged. A same-name match never authorizes an arbitrary target, +owner denials remain denials, and mismatched response types are rejected. + +Four causal regression cases cover both transports, explicit type selection, +owner denial and incorrect response types. The two directly affected resource +and audit suites pass 39 cases. This does not establish runtime or all-frontend +acceptance. Token/MFA/session and human-confirmation protections are unchanged. + +This patch requires the existing Engine 0.183.361 typed resource contract. The +matching Server also includes Engine 0.183.362 for native ServiceIndex cleanup. +Both opt-in defaults and ordinary Full/legacy API behavior remain unchanged. diff --git a/package-lock.json b/package-lock.json index 7953b7ab84..a57ddc9b2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pasturestack/web-console", - "version": "1.6.202", + "version": "1.6.203", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pasturestack/web-console", - "version": "1.6.202", + "version": "1.6.203", "license": "Apache-2.0", "dependencies": { "sass": "1.103.1" diff --git a/package.json b/package.json index 50f903cd29..61543ace75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pasturestack/web-console", - "version": "1.6.202", + "version": "1.6.203", "private": true, "description": "PastureStack browser console for the compatible control platform.", "repository": { diff --git a/scripts/check-modernization-blockers b/scripts/check-modernization-blockers index 57fa64aff6..913ce5237f 100755 --- a/scripts/check-modernization-blockers +++ b/scripts/check-modernization-blockers @@ -41,8 +41,8 @@ with open('package.json', encoding='utf-8') as f: print(json.load(f).get('version', '')) PY ) -if [[ "$version" != "1.6.202" ]]; then - echo "UNEXPECTED_UI_ARTIFACT_VERSION version=$version expected=1.6.202" +if [[ "$version" != "1.6.203" ]]; then + echo "UNEXPECTED_UI_ARTIFACT_VERSION version=$version expected=1.6.203" failures=$((failures + 1)) fi diff --git a/scripts/package-webmcp-bridge.py b/scripts/package-webmcp-bridge.py index 58e70e2945..faf309fd89 100644 --- a/scripts/package-webmcp-bridge.py +++ b/scripts/package-webmcp-bridge.py @@ -11,7 +11,7 @@ import zipfile -VERSION = "0.2.4" +VERSION = "0.2.5" SOURCE_FILES = ( "LICENSE", "app/utils/ai-command-context.js", diff --git a/scripts/test-webmcp-audit.mjs b/scripts/test-webmcp-audit.mjs index e033c967b1..26fb89e888 100644 --- a/scripts/test-webmcp-audit.mjs +++ b/scripts/test-webmcp-audit.mjs @@ -24,6 +24,85 @@ function fixture(handle, transportKind = 'browser', audit) { } const find = (filters = {}, cursor) => ({family: 'audit', resourceType: 'auditLog', auditFilters: filters, ...(cursor ? {cursor} : {})}); +test('restricted Key capabilities expose explicit types and the legacy-only default boundary', async () => { + const f = fixture(undefined, 'stdio'); + const caps = await f.engine.execute('list_capabilities', {}); + const keys = caps.families.find(item => item.family === 'api-keys'); + assert.deepEqual(keys.resources.map(item => item.resourceType), ['apiKey', 'apiKeyRestricted']); + assert.equal(keys.coverageStatus, 'pending-adapter'); + assert.match(keys.reason, /apiKey only/); assert.match(keys.reason, /does not combine/); + for (const item of keys.resources) { + assert.equal(item.scope, 'global'); assert.equal(item.authorization, 'requires-server-check'); + assert.equal(item.canFind, null); assert.equal(item.canGet, null); + assert.equal(item.safeFields.includes('secretValue'), false); + assert.equal(item.safeFields.includes('publicValue'), false); + } + const command = COMMANDS.find(item => item.name === 'find_resources'); + assert.ok(command.inputSchema.properties.resourceType.enum.includes('apiKeyRestricted')); + assert.match(command.description, /apiKeyRestricted/); +}); + +test('restricted Key exact name resolves to an opaque ref and completes audit query and detail on both transports', async () => { + for (const transport of ['browser', 'stdio']) { + const f = fixture(({url, method, data}) => { + assert.equal(method, 'POST'); + if (url === 'projects/p1/aiResourceViews') { + assert.deepEqual(data, {resourceType: 'apiKeyRestricted', query: 'Exact owned Key'}); + return {body: {resourceType: 'apiKeyRestricted', data: [{id: '1c-restricted', name: 'Exact owned Key', kind: 'apiKeyRestricted', + publicValue: secret, secretValue: secret, apiKeyPolicy: {secret}}], nextMarker: null}}; + } + assert.equal(url, 'pasturestack/ai-audit-queries'); + assert.equal(data.keyId, '1c-restricted'); assert.equal(data.environmentId, 'p1'); + return reply([row('event1', {keyId: data.keyId})], {range: {from: '2026-10-01T11:50:00Z', to: '2026-10-01T12:00:00Z'}}); + }, transport); + const selected = await f.engine.execute('find_resources', {family: 'api-keys', resourceType: 'apiKeyRestricted', query: 'Exact owned Key'}); + assert.equal(selected.status, 'succeeded'); assert.equal(selected.complete, true); assert.equal(selected.items.length, 1); + assert.equal(selected.items[0].resourceType, 'apiKeyRestricted'); + const audit = await f.engine.execute('find_resources', find({lastMinutes: 10, keyRef: selected.items[0].resourceRef})); + assert.equal(audit.status, 'succeeded'); assert.equal(audit.complete, true); + const detail = await f.engine.execute('get_resource', {resourceRef: audit.items[0].resourceRef}); + assert.equal(detail.status, 'succeeded'); assert.equal(detail.fields.payloadsIncluded, false); + assert.equal(f.requests.length, 3); + assert.equal(JSON.stringify([selected, audit, detail, f.audits]).includes(secret), false); + assert.equal(JSON.stringify(selected).includes('1c-restricted'), false); + } +}); + +test('restricted Key same-name selection remains explicit by type and default never combines candidates', async () => { + const f = fixture(({url, data}) => { + if (url === 'projects/p1/aiResourceViews') return {body: {resourceType: data.resourceType, + data: [{id: data.resourceType === 'apiKey' ? 'legacy-key' : 'restricted-key', name: 'Same name'}], nextMarker: null}}; + assert.equal(url, 'pasturestack/ai-audit-queries'); + return reply([row('event1', {keyId: data.keyId})]); + }); + const legacy = await f.engine.execute('find_resources', {family: 'api-keys', query: 'Same name'}); + const restricted = await f.engine.execute('find_resources', {family: 'api-keys', resourceType: 'apiKeyRestricted', query: 'Same name'}); + assert.equal(legacy.items.length, 1); assert.equal(restricted.items.length, 1); + assert.equal(legacy.items[0].resourceType, 'apiKey'); assert.equal(restricted.items[0].resourceType, 'apiKeyRestricted'); + assert.notEqual(legacy.items[0].resourceRef, restricted.items[0].resourceRef); + for (const [selection, expected] of [[legacy, 'legacy-key'], [restricted, 'restricted-key']]) { + const result = await f.engine.execute('find_resources', find({keyRef: selection.items[0].resourceRef})); + assert.equal(result.status, 'succeeded'); assert.equal(f.requests.at(-1).data.keyId, expected); + } + assert.deepEqual(f.requests.slice(0, 2).map(item => item.data), [ + {resourceType: 'apiKey', query: 'Same name'}, {resourceType: 'apiKeyRestricted', query: 'Same name'}, + ]); +}); + +test('restricted Key owner denial and mismatched server type never yield a selectable ref', async () => { + for (const transport of ['browser', 'stdio']) for (const denied of [true, false]) { + const f = fixture(({url, data}) => { + assert.equal(url, 'projects/p1/aiResourceViews'); assert.equal(data.resourceType, 'apiKeyRestricted'); + if (denied) throw {status: 403, body: {code: 'OwnerPermissionDenied', message: secret}}; + return {body: {resourceType: 'apiKey', data: [{id: 'foreign-key', name: 'Exact owned Key', secretValue: secret}]}}; + }, transport); + const selected = await f.engine.execute('find_resources', {family: 'api-keys', resourceType: 'apiKeyRestricted', query: 'Exact owned Key'}); + assert.equal(selected.code, denied ? 'FORBIDDEN' : 'INVALID_RESPONSE'); + assert.equal(selected.items, undefined); assert.equal(f.requests.length, 1); + assert.equal(JSON.stringify([selected, f.audits]).includes(secret), false); + } +}); + test('audit workflow resolves real returned Key/project refs, freezes range and reauthorizes event detail', async () => { const f = fixture(({url, method, data}) => { if (url === 'projects/p1/aiResourceViews') { From 27ba916bcad5b747cc4a00717399b66e3de3094b Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Sun, 1 Nov 2026 13:01:24 +0800 Subject: [PATCH 2/2] fix(webmcp): clarify approval denials and qualify patched npm12 dependencies --- COMPATIBILITY.md | 4 +- README.md | 4 +- .../modal-confirm-ai-upgrade/component.js | 4 +- app/utils/ai-resource-review-labels.js | 6 + ...ass-replacement.node24-ignore-scripts.json | 6 +- docs/releases/web-console-1.6.203.md | 20 +- package-lock.json | 6 +- package.json | 2 +- scripts/check-ui-npm-audit.js | 82 +- scripts/ci | 1 + .../captures-and-lock-projection.json | 928 ++++++++++ .../npm12-after-follow-redirects.json | 1575 ++++++++++++++++ .../npm12-before-follow-redirects.json | 1632 +++++++++++++++++ scripts/test-ai-resource-confirm-errors.mjs | 135 ++ scripts/test-ui-npm-audit.js | 108 ++ scripts/test-ui-release-dependency-patches.js | 35 +- translations/de-de.yaml | 1 + translations/en-us.yaml | 1 + translations/fa-ir.yaml | 1 + translations/fil-ph.yaml | 1 + translations/fr-fr.yaml | 1 + translations/hu-hu.yaml | 1 + translations/ja-jp.yaml | 1 + translations/ko-kr.yaml | 1 + translations/pt-br.yaml | 1 + translations/ru-ru.yaml | 1 + translations/uk-ua.yaml | 1 + translations/zh-hans.yaml | 1 + translations/zh-tw.yaml | 1 + 29 files changed, 4535 insertions(+), 26 deletions(-) create mode 100644 scripts/fixtures/npm-audit/captures-and-lock-projection.json create mode 100644 scripts/fixtures/npm-audit/npm12-after-follow-redirects.json create mode 100644 scripts/fixtures/npm-audit/npm12-before-follow-redirects.json create mode 100644 scripts/test-ai-resource-confirm-errors.mjs diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 4e5fbc9a8b..862065b9c0 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -4,8 +4,8 @@ Adds restricted-Key discovery against the existing Engine361 typed contract. Default discovery remains ordinary `apiKey`; use `apiKeyRestricted` explicitly. -The assembled Server also needs Engine362 for the separately verified native -ServiceIndex cleanup repair. Publication and runtime acceptance remain pending. +The assembled Server also needs Engine363 for accurate External Service previews +and the retained native ServiceIndex cleanup repair. Publication and runtime acceptance remain pending. ## Web Console 1.6.202 / bridge 0.2.4 published diff --git a/README.md b/README.md index 3c929aa527..7fd5067e5d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,9 @@ history, authorship, licenses, and dependency notices. Restricted API Keys gain the same name-based discovery and audit-reference flow as ordinary Keys. Select `apiKeyRestricted` explicitly; the default searches `apiKey` only. This is partial family coverage, not a merged search or complete -frontend automation. Publication and designated QA acceptance remain pending. +frontend automation. Confirmation errors gain clear permission guidance in all +thirteen locales, and follow-redirects uses its official 1.16.2 patch. Publication +and designated QA acceptance remain pending. ## Current component diff --git a/app/components/modal-confirm-ai-upgrade/component.js b/app/components/modal-confirm-ai-upgrade/component.js index 26e8f42e40..356079160b 100644 --- a/app/components/modal-confirm-ai-upgrade/component.js +++ b/app/components/modal-confirm-ai-upgrade/component.js @@ -2,7 +2,7 @@ import { computed } from '@ember/object'; import { alias } from '@ember/object/computed'; import { service } from '@ember/service'; import ModalBase from 'lacsso/components/modal-base'; -import { resourceReviewLabels } from 'ui/utils/ai-resource-review-labels'; +import { resourceReviewLabels, resourceConfirmationErrorKey } from 'ui/utils/ai-resource-review-labels'; import { createCatalogHumanForm } from 'ui/utils/ai-catalog-human-form'; import { observer } from '@ember/object'; @@ -140,7 +140,7 @@ export default ModalBase.extend({ return this.get('commands').confirmPendingPlan().then((result) => { if (this.isDestroyed || this.isDestroying) { return; } if (result.status !== 'succeeded' || result.confirmationState !== 'approved') { - this.set('errors', [this.get('intl').t(result.code === 'STALE_REFERENCE' || result.code === 'CONTEXT_CHANGED' ? 'webmcp.stale' : 'webmcp.failed')]); + this.set('errors', [this.get('intl').t(resourceConfirmationErrorKey(result.code))]); return; } this.set('approved', true); diff --git a/app/utils/ai-resource-review-labels.js b/app/utils/ai-resource-review-labels.js index 6c89999352..b0d5f67b4a 100644 --- a/app/utils/ai-resource-review-labels.js +++ b/app/utils/ai-resource-review-labels.js @@ -12,6 +12,12 @@ const STATES = {active: 'formPorts.preflight.state.active', inactive: 'formPorts removed: 'webmcp.removedState', mixed: 'webmcp.mixedState', empty: 'webmcp.emptyStack', start: 'action.start', stop: 'action.stop', restart: 'action.restart', remove: 'action.remove'}; +// Only an already sanitized public code selects fixed human guidance. +export function resourceConfirmationErrorKey(code) { + if ( code === 'FORBIDDEN' ) { return 'webmcp.forbidden'; } + return ['CONFLICT', 'SESSION_REQUIRED', 'STALE_REFERENCE', 'STALE_REF', 'CONTEXT_CHANGED'].includes(code) ? 'webmcp.stale' : 'webmcp.failed'; +} + // UI text only. Keep the immutable plan and its exact JSON program values intact. export function resourceReviewLabels(plan, translate) { const text = (key) => String(translate(key || 'generic.unknown')); diff --git a/docs/baselines/npm-package-lock.sass-replacement.node24-ignore-scripts.json b/docs/baselines/npm-package-lock.sass-replacement.node24-ignore-scripts.json index a57ddc9b2a..41fde9f70a 100644 --- a/docs/baselines/npm-package-lock.sass-replacement.node24-ignore-scripts.json +++ b/docs/baselines/npm-package-lock.sass-replacement.node24-ignore-scripts.json @@ -12697,9 +12697,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.1.tgz", - "integrity": "sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.2.tgz", + "integrity": "sha512-/kVP2U8z596Ia0gwFrwyIeo74ta5aVmSeU1FfAUMAmcEP5EP7zydmag3SLiN64NaRKef3lxsq7i/g7ltJQDGow==", "dev": true, "funding": [ { diff --git a/docs/releases/web-console-1.6.203.md b/docs/releases/web-console-1.6.203.md index c00e80b822..585d038265 100644 --- a/docs/releases/web-console-1.6.203.md +++ b/docs/releases/web-console-1.6.203.md @@ -18,5 +18,23 @@ and audit suites pass 39 cases. This does not establish runtime or all-frontend acceptance. Token/MFA/session and human-confirmation protections are unchanged. This patch requires the existing Engine 0.183.361 typed resource contract. The -matching Server also includes Engine 0.183.362 for native ServiceIndex cleanup. +matching Server also includes Engine 0.183.363, retaining ServiceIndex cleanup +and correcting External Service review before values. Both opt-in defaults and ordinary Full/legacy API behavior remain unchanged. + +## Clear confirmation errors and official dependency fix + +Rejected human approvals now use the existing alert style with a clear account/Key +permission message in all thirteen locales. Conflict, changed-session and stale +references prompt a new preview. Unknown failures remain generic; arbitrary server +messages and private payloads are never displayed. Authorization and the saving +lock/finally lifecycle are unchanged. Six focused cases cover the public error +contract, safe text, cleanup and actual locale parsing. + +The build dependency follow-redirects is pinned to official 1.16.2 for +[CVE-2026-116689](https://github.com/advisories/GHSA-mrwp-f3q8-3g9p). Real loopback +cases retain same-origin behavior and stop cross-realm sensitive headers from +following cross-origin redirects. The npm12 audit parser separately recognizes +lock-proven aliases and exact duplicate causes while retaining distinct advisory +source/range, raw findings and all existing High/Critical/review-expiry gates. +This is not a new vulnerability exception or a claim of zero Moderate findings. diff --git a/package-lock.json b/package-lock.json index a57ddc9b2a..41fde9f70a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12697,9 +12697,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.1.tgz", - "integrity": "sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.2.tgz", + "integrity": "sha512-/kVP2U8z596Ia0gwFrwyIeo74ta5aVmSeU1FfAUMAmcEP5EP7zydmag3SLiN64NaRKef3lxsq7i/g7ltJQDGow==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 61543ace75..ce7e9dd342 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "ember-cli-htmlbars": "7.0.1", "engine.io": "6.6.10", "fast-uri": "3.1.9", - "follow-redirects": "1.16.1", + "follow-redirects": "1.16.2", "@xmldom/xmldom": "0.9.12", "js-yaml": "4.3.2", "morgan": "1.12.1", diff --git a/scripts/check-ui-npm-audit.js b/scripts/check-ui-npm-audit.js index 87f3819dc3..64a5e422ed 100644 --- a/scripts/check-ui-npm-audit.js +++ b/scripts/check-ui-npm-audit.js @@ -4,6 +4,7 @@ // not a fix, a runtime VEX claim, or permission to ship the affected modules. const fs = require('node:fs'); const path = require('node:path'); +const { createHash } = require('node:crypto'); const { spawnSync } = require('node:child_process'); const ADVISORY = 'https://github.com/advisories/GHSA-vfj7-8cjw-p6xm'; @@ -129,6 +130,63 @@ function readReviewedSources(repoRoot, io = fs) { return sources; } + +// npm12 can repeat the same meta cause and report installed npm aliases under +// their actual package name. Preserve raw bytes; normalize only exact values. +function canonical(value) { + if (Array.isArray(value)) return '[' + value.map(canonical).join(',') + ']'; + if (plain(value)) return '{' + Object.keys(value).sort().map(k => JSON.stringify(k) + ':' + canonical(value[k])).join(',') + '}'; + return JSON.stringify(value); +} +function exactVia(via) { + if (!Array.isArray(via)) return via; + const seen = new Set(); + return via.filter(item => { const key = canonical(item); if (seen.has(key)) return false; seen.add(key); return true; }); +} +function aliasPairs(packages, name, nodes) { + const result = []; + for (const wrapper of nodes) { + if (!plain(packages[wrapper]) || packageName(wrapper) !== name) continue; + for (const [alias, spec] of Object.entries({ ...packages[wrapper].dependencies, ...packages[wrapper].optionalDependencies })) { + const target = resolveDependency(packages, wrapper, alias), item = packages[target]; + if (nodes.includes(target) && packageName(target) === alias && alias !== name && plain(item) && item.name === name && + packages[wrapper].version === item.version && spec === `npm:${name}@${item.version}`) result.push({wrapper, target}); + } + } + return result; +} +function auditNodeMatches(packages, node, name) { + const item = packages[node]; + if (!plain(item)) return false; + if (packageName(node) === name) return item.name === undefined || item.name === name; + if (item.name !== name) return false; + const alias = packageName(node); + return Object.entries(packages).some(([from, owner]) => plain(owner) && + { ...owner.dependencies, ...owner.optionalDependencies, ...(!from ? owner.devDependencies : {}) }[alias] === `npm:${name}@${item.version}` && + resolveDependency(packages, from, alias) === node); +} +const advisoryHash = (name, source) => createHash('sha512').update(JSON.stringify([name, source])).digest('base64'); +function calculatedAdvisory(via, name, vulnerability, vulnerabilities, packages) { + if (!plain(via) || typeof via.source !== 'string' || !/^[A-Za-z0-9+/]{86}==$/.test(via.source) || + via.range !== '*' || !aliasPairs(packages, name, vulnerability.nodes).length) return false; + const official = item => plain(item) && Number.isSafeInteger(item.source) && item.source > 0; + if (typeof via.url === 'string') return vulnerability.via.some(item => official(item) && + via.source === advisoryHash(name, item.source) && canonical({...via, source: item.source, range: item.range}) === canonical(item)); + if (via.url !== null) return false; + return vulnerability.via.some(child => { + if (typeof child !== 'string' || !plain(vulnerabilities[child]) || !aliasPairs(packages, child, vulnerabilities[child].nodes).length) return false; + const realEdge = aliasPairs(packages, name, vulnerability.nodes).some(pair => { + const declared = {...packages[pair.target].dependencies, ...packages[pair.target].optionalDependencies}; + const target = resolveDependency(packages, pair.target, child); + return typeof declared[child] === 'string' && vulnerabilities[child].nodes.includes(target) && auditNodeMatches(packages, target, child); + }); + return realEdge && vulnerabilities[child].via.some(item => official(item) && + via.source === advisoryHash(name, advisoryHash(child, item.source)) && + via.title === `Depends on vulnerable versions of ${child}` && via.severity === item.severity && + canonical(via.cwe) === canonical(item.cwe) && canonical(via.cvss) === canonical(item.cvss)); + }); +} + function evaluateAudit({ audit, lock, pending, now = new Date(), npmExitCode }) { let totals = null; try { @@ -146,7 +204,8 @@ function evaluateAudit({ audit, lock, pending, now = new Date(), npmExitCode }) need(totals.critical === 0, 'CRITICAL_VULNERABILITY'); need(sameSet(Object.keys(audit.metadata.dependencies), ['prod', 'dev', 'optional', 'peer', 'peerOptional', 'total']) && Object.values(audit.metadata.dependencies).every(n => Number.isSafeInteger(n) && n >= 0), 'NPM_AUDIT_DEPENDENCIES_INVALID'); - const vulnerabilities = audit.vulnerabilities; + const vulnerabilities = Object.fromEntries(Object.entries(audit.vulnerabilities).map(([name, v]) => + [name, plain(v) ? {...v, via: exactVia(v.via)} : v])); const observed = Object.fromEntries(LEVELS.map(k => [k, 0])); const allowedKeys = ['name', 'severity', 'isDirect', 'via', 'effects', 'range', 'nodes', 'fixAvailable']; for (const [name, v] of Object.entries(vulnerabilities)) { @@ -156,21 +215,22 @@ function evaluateAudit({ audit, lock, pending, now = new Date(), npmExitCode }) (typeof v.fixAvailable === 'boolean' || (plain(v.fixAvailable) && typeof v.fixAvailable.name === 'string' && typeof v.fixAvailable.version === 'string' && typeof v.fixAvailable.isSemVerMajor === 'boolean')), 'NPM_VULNERABILITY_SHAPE_INVALID'); observed[v.severity]++; - for (const node of v.nodes) need(plain(packages[node]) && packageName(node) === name, 'AUDIT_NODE_LOCK_MISMATCH'); + for (const node of v.nodes) need(auditNodeMatches(packages, node, name), 'AUDIT_NODE_LOCK_MISMATCH'); for (const e of v.effects) need(own(vulnerabilities, e), 'AUDIT_EFFECT_REFERENCE_INVALID'); - need(new Set(v.via.map(x => typeof x === 'string' ? 'meta:' + x : 'advisory:' + x?.url)).size === v.via.length, - 'AUDIT_VIA_DUPLICATE'); for (const via of v.via) { if (typeof via === 'string') { need(own(vulnerabilities, via), 'AUDIT_VIA_REFERENCE_INVALID'); need(LEVELS.indexOf(v.severity) >= LEVELS.indexOf(vulnerabilities[via].severity), 'AUDIT_SEVERITY_INCONSISTENT'); } - else need(plain(via) && Object.keys(via).every(k => ['source', 'name', 'dependency', 'title', 'url', 'severity', 'cwe', 'cvss', 'range'].includes(k)) && - Number.isSafeInteger(via.source) && via.source > 0 && via.name === name && - via.dependency === name && typeof via.title === 'string' && typeof via.url === 'string' && - /^https:\/\/github\.com\/advisories\/GHSA-[a-z0-9-]+$/.test(via.url) && LEVELS.includes(via.severity) && - typeof via.range === 'string' && strings(via.cwe) && plain(via.cvss) && Number.isFinite(via.cvss.score) && - (via.cvss.vectorString === null || typeof via.cvss.vectorString === 'string'), 'AUDIT_ADVISORY_SHAPE_INVALID'); + else { + const calculated = calculatedAdvisory(via, name, v, vulnerabilities, packages); + need(plain(via) && Object.keys(via).every(k => ['source', 'name', 'dependency', 'title', 'url', 'severity', 'cwe', 'cvss', 'range'].includes(k)) && + (Number.isSafeInteger(via.source) && via.source > 0 || calculated) && via.name === name && + via.dependency === name && typeof via.title === 'string' && + (typeof via.url === 'string' && /^https:\/\/github\.com\/advisories\/GHSA-[a-z0-9-]+$/.test(via.url) || calculated && via.url === null) && LEVELS.includes(via.severity) && + typeof via.range === 'string' && strings(via.cwe) && plain(via.cvss) && Number.isFinite(via.cvss.score) && + (via.cvss.vectorString === null || typeof via.cvss.vectorString === 'string'), 'AUDIT_ADVISORY_SHAPE_INVALID'); + } if (typeof via !== 'string') need(LEVELS.indexOf(v.severity) >= LEVELS.indexOf(via.severity), 'AUDIT_SEVERITY_INCONSISTENT'); } } @@ -281,7 +341,7 @@ function runAudit(repoRoot, runner = spawnSync, platform = process.platform, clo return evaluateAudit({ audit, lock, pending, now: clock(), npmExitCode: result.status }); } -module.exports = { evaluateAudit, validatePending, validateReviewedImports, readReviewedSources, npmInvocation, runAudit }; +module.exports = { exactVia, evaluateAudit, validatePending, validateReviewedImports, readReviewedSources, npmInvocation, runAudit }; if (require.main === module) { const result = runAudit(path.resolve(__dirname, '..')); console.log(JSON.stringify(result)); diff --git a/scripts/ci b/scripts/ci index 7b7ff4e22c..7904f2af55 100755 --- a/scripts/ci +++ b/scripts/ci @@ -18,6 +18,7 @@ node --test scripts/test-webmcp-certificate-metadata.mjs node --test scripts/test-webmcp-audit.mjs scripts/test-webmcp-audit-extension.mjs node scripts/test-ai-collaboration-ui.js node scripts/test-ai-resource-review-labels.mjs +node --test scripts/test-ai-resource-confirm-errors.mjs ./scripts/check-ui-catalog-version-select node ./scripts/check-ui-catalog-form-contract.js node ./scripts/check-ui-code-block-contrast.js diff --git a/scripts/fixtures/npm-audit/captures-and-lock-projection.json b/scripts/fixtures/npm-audit/captures-and-lock-projection.json new file mode 100644 index 0000000000..7720192642 --- /dev/null +++ b/scripts/fixtures/npm-audit/captures-and-lock-projection.json @@ -0,0 +1,928 @@ +{ + "schemaVersion": 1, + "description": "Exact public npm12 primary report bytes and a projection of only lock fields/edges needed by these policy fixtures. Full originals and original-parser causal RED are retained outside the repository. These are not the failed CI run bytes.", + "captures": { + "before": { + "rawFile": "npm12-before-follow-redirects.json", + "rawSha256": "5edfeda930b767ab22fb4b769ef61aa306260821d13faa1d0809cde4030ce5e0", + "capturedUtc": "2026-11-01T04:10:05.907Z", + "npmExitCode": 1, + "nodeVersion": "v24.22.1", + "npmVersion": "12.0.2", + "sourceCommit": "1c0ddbad342e21d23e898133706fa7e9fcb738fc", + "sourceLockSha256": "60a8b04ec29068ca0939ee702b905afb3caa17edc0f26474d50438323a093a88", + "sourceParserSha256": "f3bfebdd047e6111cd198d7be3d03a92863c66dc99549f4d15d05641cd5dee4d", + "sourcePendingSha256": "d09b6834b4610a4984ff0e0390ffc477075898df2f541ae62c147bf40df1c2ca", + "originalParserFailureCode": "AUDIT_VIA_DUPLICATE" + }, + "after": { + "rawFile": "npm12-after-follow-redirects.json", + "rawSha256": "76e1aba28fbb0d18cdfaeaceab1588f17b3944c52f778cbf2bcbc7b4c11bc816", + "capturedUtc": "2026-11-01T04:14:39.264Z", + "npmExitCode": 0, + "nodeVersion": "v24.22.1", + "npmVersion": "12.0.2", + "sourceCommit": "1c0ddbad342e21d23e898133706fa7e9fcb738fc", + "sourceLockSha256": "a0dfad456f43949e8c7c707197a0d73c2bb54b1a2a6d0ce763db1e3be7038452", + "sourceParserSha256": "f3bfebdd047e6111cd198d7be3d03a92863c66dc99549f4d15d05641cd5dee4d", + "sourcePendingSha256": "d09b6834b4610a4984ff0e0390ffc477075898df2f541ae62c147bf40df1c2ca", + "originalParserFailureCode": "AUDIT_VIA_DUPLICATE" + } + }, + "lock": { + "lockfileVersion": 3, + "packages": { + "": { + "name": "@pasturestack/web-console", + "version": "1.6.203", + "dependencies": { + "sass": "1.103.1" + } + }, + "node_modules/@ember-tooling/blueprint-model": { + "version": "0.7.1" + }, + "node_modules/@ember-tooling/blueprint-model/node_modules/minimatch": { + "version": "10.2.6" + }, + "node_modules/@ember-tooling/blueprint-model/node_modules/walk-sync": { + "version": "4.0.2" + }, + "node_modules/@ember-tooling/classic-build-addon-blueprint": { + "version": "7.2.0" + }, + "node_modules/@ember-tooling/classic-build-addon-blueprint/node_modules/walk-sync": { + "version": "3.0.0" + }, + "node_modules/@ember-tooling/classic-build-app-blueprint": { + "version": "7.2.0" + }, + "node_modules/@ember/app-blueprint": { + "version": "7.2.1" + }, + "node_modules/@ember/app-blueprint/node_modules/minimatch": { + "version": "10.2.6" + }, + "node_modules/@ember/app-blueprint/node_modules/walk-sync": { + "version": "4.0.2" + }, + "node_modules/@ember/legacy-built-in-components": { + "version": "0.5.0" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/babel-plugin-module-resolver": { + "version": "3.2.0" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-babel-transpiler": { + "version": "7.8.1" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-funnel": { + "version": "2.0.2" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-funnel/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-merge-trees": { + "version": "3.0.2" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter": { + "version": "2.3.1" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter/node_modules/walk-sync": { + "version": "1.1.4" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-plugin/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/ember-cli-babel": { + "version": "7.26.11" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/matcher-collection": { + "version": "1.1.2" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/@ember/legacy-built-in-components/node_modules/sync-disk-cache/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/@embroider/addon-shim": { + "version": "1.10.3" + }, + "node_modules/@embroider/addon-shim/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "node_modules/@embroider/addon-shim/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/@embroider/addon-shim/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/@embroider/addon-shim/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/@embroider/addon-shim/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/@embroider/macros": { + "version": "1.20.5" + }, + "node_modules/@embroider/shared-internals": { + "version": "3.1.1" + }, + "node_modules/async-disk-cache": { + "version": "1.3.5" + }, + "node_modules/async-disk-cache/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/async-disk-cache/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/babel-plugin-module-resolver": { + "version": "5.0.3" + }, + "node_modules/babel-plugin-module-resolver/node_modules/glob": { + "version": "9.3.5" + }, + "node_modules/babel-plugin-module-resolver/node_modules/minimatch": { + "version": "8.0.7" + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true + }, + "node_modules/broccoli": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/broccoli/-/broccoli-4.0.0.tgz", + "integrity": "sha512-p5el5/ig0QeRGFPkLMPdm7KblkTm44eicEWfwnRTz6hncghVuRZ0+XDAtCi7ynxobeE/mey5Q7lAulFkgNzxVA==", + "dev": true, + "dependencies": { + "findup-sync": "^5.0.0", + "sane": "^5.0.1" + } + }, + "node_modules/broccoli-asset-rev": { + "version": "3.0.0" + }, + "node_modules/broccoli-asset-rewrite": { + "version": "2.0.0" + }, + "node_modules/broccoli-babel-transpiler": { + "version": "8.0.2" + }, + "node_modules/broccoli-babel-transpiler/node_modules/async-disk-cache": { + "version": "2.1.0" + }, + "node_modules/broccoli-babel-transpiler/node_modules/broccoli-persistent-filter": { + "version": "3.1.3" + }, + "node_modules/broccoli-babel-transpiler/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/broccoli-babel-transpiler/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-babel-transpiler/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/broccoli-caching-writer": { + "version": "3.1.0" + }, + "node_modules/broccoli-caching-writer/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-caching-writer/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-caching-writer/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/broccoli-concat": { + "version": "4.2.7" + }, + "node_modules/broccoli-concat/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/broccoli-concat/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-concat/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/broccoli-config-loader": { + "version": "1.0.1" + }, + "node_modules/broccoli-config-replace": { + "version": "1.1.3" + }, + "node_modules/broccoli-config-replace/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-config-replace/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-config-replace/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/broccoli-debug": { + "version": "0.6.5" + }, + "node_modules/broccoli-debug/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-debug/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-debug/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/broccoli-file-creator": { + "version": "2.1.1" + }, + "node_modules/broccoli-file-creator/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-file-creator/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-file-creator/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/broccoli-filter": { + "version": "1.3.0" + }, + "node_modules/broccoli-filter/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-filter/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-filter/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/broccoli-funnel": { + "version": "4.0.0" + }, + "node_modules/broccoli-funnel/node_modules/minimatch": { + "version": "10.2.6" + }, + "node_modules/broccoli-funnel/node_modules/walk-sync": { + "version": "4.0.2" + }, + "node_modules/broccoli-kitchen-sink-helpers": { + "version": "0.3.1" + }, + "node_modules/broccoli-kitchen-sink-helpers/node_modules/glob": { + "version": "5.0.15" + }, + "node_modules/broccoli-merge-trees": { + "version": "4.2.0" + }, + "node_modules/broccoli-merge-trees/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/broccoli-merge-trees/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-merge-trees/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/broccoli-persistent-filter": { + "version": "1.4.6" + }, + "node_modules/broccoli-persistent-filter/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-persistent-filter/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-persistent-filter/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/broccoli-plugin": { + "version": "6.0.0" + }, + "node_modules/broccoli-sass-source-maps": { + "version": "4.3.0" + }, + "node_modules/broccoli-stew": { + "version": "3.0.0" + }, + "node_modules/broccoli-stew/node_modules/broccoli-funnel": { + "version": "2.0.2" + }, + "node_modules/broccoli-stew/node_modules/broccoli-funnel/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-stew/node_modules/broccoli-funnel/node_modules/walk-sync": { + "version": "0.3.4" + }, + "node_modules/broccoli-stew/node_modules/broccoli-merge-trees": { + "version": "3.0.2" + }, + "node_modules/broccoli-stew/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-stew/node_modules/broccoli-persistent-filter": { + "version": "2.3.1" + }, + "node_modules/broccoli-stew/node_modules/broccoli-persistent-filter/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/broccoli-stew/node_modules/broccoli-plugin": { + "version": "2.1.0" + }, + "node_modules/broccoli-stew/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-stew/node_modules/matcher-collection": { + "version": "1.1.2" + }, + "node_modules/broccoli-stew/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/broccoli-stew/node_modules/walk-sync": { + "version": "1.1.4" + }, + "node_modules/broccoli-string-replace": { + "version": "0.1.2" + }, + "node_modules/broccoli-terser-sourcemap": { + "version": "4.1.1" + }, + "node_modules/broccoli-terser-sourcemap/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/broccoli-terser-sourcemap/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/broccoli-terser-sourcemap/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/broccoli-terser-sourcemap/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/broccoli/node_modules/tree-sync": { + "version": "2.1.0" + }, + "node_modules/ejs": { + "version": "3.1.10" + }, + "node_modules/ember-api-store": { + "version": "2.8.5" + }, + "node_modules/ember-api-store/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "node_modules/ember-api-store/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/ember-api-store/node_modules/ember-cli-babel": { + "version": "8.3.1" + }, + "node_modules/ember-api-store/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/ember-api-store/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/ember-api-store/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/ember-auto-import": { + "version": "2.13.1" + }, + "node_modules/ember-auto-import/node_modules/@embroider/shared-internals": { + "version": "2.9.2" + }, + "node_modules/ember-auto-import/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "node_modules/ember-auto-import/node_modules/broccoli-funnel/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/ember-auto-import/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/ember-auto-import/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/ember-auto-import/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/ember-auto-import/node_modules/walk-sync": { + "version": "3.0.0" + }, + "node_modules/ember-basic-dropdown": { + "version": "9.0.0" + }, + "node_modules/ember-cli": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ember-cli/-/ember-cli-7.2.0.tgz", + "integrity": "sha512-EafquLJ+EVHz0nNo32NWwAfHr5UxTXn9zdlukuKZFSFrR4G6RRStmBPQ5O0bLSaQVDtU+jOe5gGTHSS4Xy3uQA==", + "dev": true, + "dependencies": { + "broccoli": "^4.0.0", + "find-yarn-workspace-root": "^2.0.0", + "sane": "^5.0.1" + } + }, + "node_modules/ember-cli-babel": { + "version": "8.3.2" + }, + "node_modules/ember-cli-babel/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "node_modules/ember-cli-babel/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/ember-cli-babel/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/ember-cli-babel/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/ember-cli-babel/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/ember-cli-htmlbars": { + "version": "7.0.1" + }, + "node_modules/ember-cli-htmlbars/node_modules/async-disk-cache": { + "version": "2.1.0" + }, + "node_modules/ember-cli-htmlbars/node_modules/broccoli-persistent-filter": { + "version": "3.1.3" + }, + "node_modules/ember-cli-htmlbars/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/ember-cli-htmlbars/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/ember-cli-htmlbars/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/ember-cli-htmlbars/node_modules/walk-sync": { + "version": "4.0.2" + }, + "node_modules/ember-cli-htmlbars/node_modules/walk-sync/node_modules/minimatch": { + "version": "10.2.6" + }, + "node_modules/ember-cli-preprocess-registry": { + "version": "5.0.1" + }, + "node_modules/ember-cli-preprocess-registry/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "node_modules/ember-cli-preprocess-registry/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/ember-cli-preprocess-registry/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/ember-cli-preprocess-registry/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/ember-cli-preprocess-registry/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/ember-cli-sass": { + "version": "11.0.1" + }, + "node_modules/ember-cli-sass/node_modules/broccoli-funnel": { + "version": "2.0.2" + }, + "node_modules/ember-cli-sass/node_modules/broccoli-merge-trees": { + "version": "3.0.2" + }, + "node_modules/ember-cli-sass/node_modules/broccoli-plugin": { + "version": "1.3.1" + }, + "node_modules/ember-cli-sass/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/ember-cli-sass/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/ember-cli-terser": { + "version": "4.0.2" + }, + "node_modules/ember-cli-typescript": { + "version": "4.2.1" + }, + "node_modules/ember-cli-typescript/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/ember-cli/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "node_modules/ember-cli/node_modules/broccoli-funnel/node_modules/minimatch": { + "version": "3.1.5" + }, + "node_modules/ember-cli/node_modules/broccoli-funnel/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/ember-cli/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/ember-cli/node_modules/minimatch": { + "version": "10.2.6" + }, + "node_modules/ember-cli/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/ember-cli/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/ember-cli/node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.5" + }, + "node_modules/ember-cli/node_modules/tree-sync": { + "version": "2.1.0" + }, + "node_modules/ember-cli/node_modules/tree-sync/node_modules/matcher-collection": { + "version": "1.1.2" + }, + "node_modules/ember-cli/node_modules/tree-sync/node_modules/minimatch": { + "version": "3.1.5" + }, + "node_modules/ember-cli/node_modules/tree-sync/node_modules/walk-sync": { + "version": "0.3.4" + }, + "node_modules/ember-cli/node_modules/walk-sync": { + "version": "4.0.2" + }, + "node_modules/ember-fetch": { + "version": "5.1.3" + }, + "node_modules/ember-fetch/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "node_modules/ember-fetch/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "node_modules/ember-fetch/node_modules/ember-cli-babel": { + "version": "8.3.1" + }, + "node_modules/ember-fetch/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/ember-fetch/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/ember-fetch/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/ember-load-initializers": { + "version": "3.0.1" + }, + "node_modules/ember-power-select": { + "version": "9.0.2" + }, + "node_modules/ember-source": { + "version": "7.2.0" + }, + "node_modules/filelist": { + "version": "1.0.6" + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9" + }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.2" + } + }, + "node_modules/findup-sync": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.4" + } + }, + "node_modules/fixturify": { + "version": "1.3.0" + }, + "node_modules/fixturify-project": { + "version": "1.10.0" + }, + "node_modules/follow-redirects": { + "version": "1.16.1" + }, + "node_modules/fs-merger": { + "version": "3.2.1" + }, + "node_modules/fs-merger/node_modules/walk-sync": { + "version": "2.2.0" + }, + "node_modules/fs-updater": { + "version": "1.0.4" + }, + "node_modules/fs-updater/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/fs-updater/node_modules/rimraf": { + "version": "2.7.1" + }, + "node_modules/glob": { + "version": "13.0.6", + "dependencies": { + "glob-real": "npm:glob@13.0.6" + } + }, + "node_modules/glob-real": { + "name": "glob", + "version": "13.0.6" + }, + "node_modules/glob-real/node_modules/minimatch": { + "version": "10.2.6" + }, + "node_modules/jake": { + "version": "10.9.4" + }, + "node_modules/matcher-collection": { + "version": "2.0.1" + }, + "node_modules/merge-trees": { + "version": "2.0.0" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3" + } + }, + "node_modules/minimatch": { + "version": "3.1.5" + }, + "node_modules/quick-temp": { + "version": "0.1.9" + }, + "node_modules/quick-temp/node_modules/glob": { + "version": "10.5.0" + }, + "node_modules/quick-temp/node_modules/minimatch": { + "version": "9.0.9" + }, + "node_modules/quick-temp/node_modules/rimraf": { + "version": "5.0.10" + }, + "node_modules/rimraf": { + "version": "6.1.3", + "dependencies": { + "rimraf-real": "npm:rimraf@6.1.3" + } + }, + "node_modules/rimraf-real": { + "name": "rimraf", + "version": "6.1.3", + "dependencies": { + "glob": "^13.0.3" + } + }, + "node_modules/sane": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/sane/-/sane-5.0.1.tgz", + "integrity": "sha512-9/0CYoRz0MKKf04OMCO3Qk3RQl1PAwWAhPSQSym4ULiLpTZnrY1JoZU0IEikHu8kdk2HvKT/VwQMq/xFZ8kh1Q==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.2" + } + }, + "node_modules/sass": { + "version": "1.103.1" + }, + "node_modules/sync-disk-cache": { + "version": "2.1.0" + }, + "node_modules/sync-disk-cache/node_modules/glob": { + "version": "7.2.3" + }, + "node_modules/sync-disk-cache/node_modules/rimraf": { + "version": "3.0.2" + }, + "node_modules/testem": { + "version": "3.20.0" + }, + "node_modules/testem/node_modules/consolidate": { + "version": "1.0.4" + }, + "node_modules/testem/node_modules/minimatch": { + "version": "10.2.6" + }, + "node_modules/tree-sync": { + "version": "1.4.0" + }, + "node_modules/walk-sync": { + "version": "0.3.4" + }, + "node_modules/walk-sync/node_modules/matcher-collection": { + "version": "1.1.2" + }, + "node_modules/yamljs": { + "version": "0.3.0" + }, + "node_modules/yamljs/node_modules/glob": { + "version": "7.2.3" + }, + "vendor/ember-cli-pagination/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "vendor/ember-cli-pagination/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "vendor/ember-cli-pagination/node_modules/ember-cli-babel": { + "version": "8.3.1" + }, + "vendor/ember-cli-pagination/node_modules/glob": { + "version": "7.2.3" + }, + "vendor/ember-cli-pagination/node_modules/rimraf": { + "version": "3.0.2" + }, + "vendor/ember-cli-pagination/node_modules/walk-sync": { + "version": "2.2.0" + }, + "vendor/ember-rl-dropdown/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "vendor/ember-rl-dropdown/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "vendor/ember-rl-dropdown/node_modules/ember-cli-babel": { + "version": "8.3.1" + }, + "vendor/ember-rl-dropdown/node_modules/glob": { + "version": "7.2.3" + }, + "vendor/ember-rl-dropdown/node_modules/rimraf": { + "version": "3.0.2" + }, + "vendor/ember-rl-dropdown/node_modules/walk-sync": { + "version": "2.2.0" + }, + "vendor/lacsso/node_modules/broccoli-funnel": { + "version": "3.0.8" + }, + "vendor/lacsso/node_modules/broccoli-plugin": { + "version": "4.0.7" + }, + "vendor/lacsso/node_modules/ember-cli-babel": { + "version": "8.3.1" + }, + "vendor/lacsso/node_modules/glob": { + "version": "7.2.3" + }, + "vendor/lacsso/node_modules/rimraf": { + "version": "3.0.2" + }, + "vendor/lacsso/node_modules/walk-sync": { + "version": "2.2.0" + } + } + }, + "pending": { + "schemaVersion": 1, + "advisoryUrl": "https://github.com/advisories/GHSA-vfj7-8cjw-p6xm", + "severity": "high", + "upstreamPatchedVersion": null, + "scope": "controlled-dev-build-inputs-only", + "publicationBlockedIfShippedNodes": true, + "shippedNodes": [], + "advisoryStatus": "withdrawn", + "advisoryWithdrawnAt": "2026-10-23T12:53:02Z", + "upstreamLatestVersion": "3.0.3", + "officialStatusSources": [ + "https://github.com/advisories/GHSA-vfj7-8cjw-p6xm", + "https://api.github.com/advisories/GHSA-vfj7-8cjw-p6xm", + "https://registry.npmjs.org/braces/latest" + ], + "reviewUntil": "2026-11-05", + "reviewedAt": "2026-10-29T09:27:01Z", + "nodes": [ + { + "path": "node_modules/braces", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true + }, + { + "path": "node_modules/micromatch", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true + }, + { + "path": "node_modules/findup-sync", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "dev": true + }, + { + "path": "node_modules/find-yarn-workspace-root", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true + }, + { + "path": "node_modules/sane", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/sane/-/sane-5.0.1.tgz", + "integrity": "sha512-9/0CYoRz0MKKf04OMCO3Qk3RQl1PAwWAhPSQSym4ULiLpTZnrY1JoZU0IEikHu8kdk2HvKT/VwQMq/xFZ8kh1Q==", + "dev": true + }, + { + "path": "node_modules/broccoli", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/broccoli/-/broccoli-4.0.0.tgz", + "integrity": "sha512-p5el5/ig0QeRGFPkLMPdm7KblkTm44eicEWfwnRTz6hncghVuRZ0+XDAtCi7ynxobeE/mey5Q7lAulFkgNzxVA==", + "dev": true + }, + { + "path": "node_modules/ember-cli", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ember-cli/-/ember-cli-7.2.0.tgz", + "integrity": "sha512-EafquLJ+EVHz0nNo32NWwAfHr5UxTXn9zdlukuKZFSFrR4G6RRStmBPQ5O0bLSaQVDtU+jOe5gGTHSS4Xy3uQA==", + "dev": true + } + ], + "edges": [ + { + "from": "node_modules/micromatch", + "to": "node_modules/braces", + "spec": "^3.0.3" + }, + { + "from": "node_modules/findup-sync", + "to": "node_modules/micromatch", + "spec": "^4.0.4" + }, + { + "from": "node_modules/find-yarn-workspace-root", + "to": "node_modules/micromatch", + "spec": "^4.0.2" + }, + { + "from": "node_modules/sane", + "to": "node_modules/micromatch", + "spec": "^4.0.2" + }, + { + "from": "node_modules/broccoli", + "to": "node_modules/findup-sync", + "spec": "^5.0.0" + }, + { + "from": "node_modules/broccoli", + "to": "node_modules/sane", + "spec": "^5.0.1" + }, + { + "from": "node_modules/ember-cli", + "to": "node_modules/broccoli", + "spec": "^4.0.0" + }, + { + "from": "node_modules/ember-cli", + "to": "node_modules/find-yarn-workspace-root", + "spec": "^2.0.0" + }, + { + "from": "node_modules/ember-cli", + "to": "node_modules/sane", + "spec": "^5.0.1" + } + ] + }, + "patchedFollowRedirectsNode": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.2.tgz", + "integrity": "sha512-/kVP2U8z596Ia0gwFrwyIeo74ta5aVmSeU1FfAUMAmcEP5EP7zydmag3SLiN64NaRKef3lxsq7i/g7ltJQDGow==", + "dev": true + } +} diff --git a/scripts/fixtures/npm-audit/npm12-after-follow-redirects.json b/scripts/fixtures/npm-audit/npm12-after-follow-redirects.json new file mode 100644 index 0000000000..b295697870 --- /dev/null +++ b/scripts/fixtures/npm-audit/npm12-after-follow-redirects.json @@ -0,0 +1,1575 @@ +{ + "auditReportVersion": 2, + "vulnerabilities": { + "@ember-tooling/blueprint-model": { + "name": "@ember-tooling/blueprint-model", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch", + "quick-temp", + "walk-sync" + ], + "effects": [ + "@ember-tooling/classic-build-addon-blueprint", + "@ember-tooling/classic-build-app-blueprint", + "ember-cli" + ], + "range": ">=0.6.2", + "nodes": [ + "node_modules/@ember-tooling/blueprint-model" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "@ember-tooling/classic-build-addon-blueprint": { + "name": "@ember-tooling/classic-build-addon-blueprint", + "severity": "moderate", + "isDirect": false, + "via": [ + "@ember-tooling/blueprint-model", + "walk-sync" + ], + "effects": [ + "ember-cli" + ], + "range": ">=6.7.0-alpha.3", + "nodes": [ + "node_modules/@ember-tooling/classic-build-addon-blueprint" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "@ember-tooling/classic-build-app-blueprint": { + "name": "@ember-tooling/classic-build-app-blueprint", + "severity": "moderate", + "isDirect": false, + "via": [ + "@ember-tooling/blueprint-model" + ], + "effects": [ + "ember-cli" + ], + "range": ">=7.1.0-alpha.1", + "nodes": [ + "node_modules/@ember-tooling/classic-build-app-blueprint" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "@ember/app-blueprint": { + "name": "@ember/app-blueprint", + "severity": "moderate", + "isDirect": false, + "via": [ + "ejs", + "walk-sync" + ], + "effects": [ + "ember-cli" + ], + "range": ">=0.1.0", + "nodes": [ + "node_modules/@ember/app-blueprint" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "@ember/legacy-built-in-components": { + "name": "@ember/legacy-built-in-components", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-cli-babel", + "ember-cli-htmlbars", + "ember-cli-typescript", + "ember-source" + ], + "effects": [], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components" + ], + "fixAvailable": { + "name": "@ember/legacy-built-in-components", + "version": "0.2.0", + "isSemVerMajor": true + } + }, + "@embroider/addon-shim": { + "name": "@embroider/addon-shim", + "severity": "moderate", + "isDirect": false, + "via": [ + "@embroider/shared-internals", + "broccoli-funnel" + ], + "effects": [], + "range": "1.8.4-unstable.00ec2e7 - 1.10.3 || >=2.0.0-alpha.0", + "nodes": [ + "node_modules/@embroider/addon-shim" + ], + "fixAvailable": true + }, + "@embroider/macros": { + "name": "@embroider/macros", + "severity": "moderate", + "isDirect": false, + "via": [ + "@embroider/shared-internals" + ], + "effects": [ + "ember-basic-dropdown" + ], + "range": ">=1.15.1", + "nodes": [ + "node_modules/@embroider/macros" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "@embroider/shared-internals": { + "name": "@embroider/shared-internals", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch" + ], + "effects": [ + "@embroider/addon-shim", + "@embroider/macros" + ], + "range": ">=2.5.3-unstable.11f2c70", + "nodes": [ + "node_modules/@embroider/shared-internals", + "node_modules/ember-auto-import/node_modules/@embroider/shared-internals" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "async-disk-cache": { + "name": "async-disk-cache", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf" + ], + "effects": [ + "broccoli-persistent-filter" + ], + "range": ">=1.0.8", + "nodes": [ + "node_modules/async-disk-cache", + "node_modules/broccoli-babel-transpiler/node_modules/async-disk-cache", + "node_modules/ember-cli-htmlbars/node_modules/async-disk-cache" + ], + "fixAvailable": false + }, + "babel-plugin-module-resolver": { + "name": "babel-plugin-module-resolver", + "severity": "moderate", + "isDirect": false, + "via": [ + "glob", + "glob" + ], + "effects": [ + "ember-cli-babel" + ], + "range": ">=2.2.0", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/babel-plugin-module-resolver", + "node_modules/babel-plugin-module-resolver" + ], + "fixAvailable": false + }, + "broccoli": { + "name": "broccoli", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf", + "tree-sync" + ], + "effects": [ + "ember-cli" + ], + "range": ">=2.0.0-beta.1", + "nodes": [ + "node_modules/broccoli" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-asset-rev": { + "name": "broccoli-asset-rev", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-asset-rewrite", + "broccoli-filter", + "broccoli-persistent-filter", + "minimatch" + ], + "effects": [], + "range": "*", + "nodes": [ + "node_modules/broccoli-asset-rev" + ], + "fixAvailable": { + "name": "broccoli-asset-rev", + "version": "2.5.0", + "isSemVerMajor": true + } + }, + "broccoli-asset-rewrite": { + "name": "broccoli-asset-rewrite", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-filter" + ], + "effects": [ + "broccoli-asset-rev" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-asset-rewrite" + ], + "fixAvailable": { + "name": "broccoli-asset-rev", + "version": "2.5.0", + "isSemVerMajor": true + } + }, + "broccoli-babel-transpiler": { + "name": "broccoli-babel-transpiler", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-persistent-filter" + ], + "effects": [ + "ember-cli-babel" + ], + "range": ">=5.3.0", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-babel-transpiler", + "node_modules/broccoli-babel-transpiler" + ], + "fixAvailable": false + }, + "broccoli-caching-writer": { + "name": "broccoli-caching-writer", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin", + "walk-sync" + ], + "effects": [ + "broccoli-config-loader", + "broccoli-sass-source-maps" + ], + "range": ">=2.0.0", + "nodes": [ + "node_modules/broccoli-caching-writer" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-concat": { + "name": "broccoli-concat", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-debug", + "broccoli-plugin" + ], + "effects": [ + "ember-cli" + ], + "range": ">=3.1.0", + "nodes": [ + "node_modules/broccoli-concat" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-config-loader": { + "name": "broccoli-config-loader", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-caching-writer" + ], + "effects": [ + "ember-cli" + ], + "range": ">=1.0.1", + "nodes": [ + "node_modules/broccoli-config-loader" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-config-replace": { + "name": "broccoli-config-replace", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin" + ], + "effects": [ + "ember-cli" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-config-replace" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-debug": { + "name": "broccoli-debug", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin", + "tree-sync" + ], + "effects": [ + "broccoli-concat", + "broccoli-stew", + "ember-auto-import", + "ember-cli", + "ember-cli-babel", + "ember-cli-htmlbars" + ], + "range": ">=0.6.0", + "nodes": [ + "node_modules/broccoli-debug" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-file-creator": { + "name": "broccoli-file-creator", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin" + ], + "effects": [ + "ember-source" + ], + "range": ">=1.0.0", + "nodes": [ + "node_modules/broccoli-file-creator" + ], + "fixAvailable": { + "name": "ember-source", + "version": "3.27.2", + "isSemVerMajor": true + } + }, + "broccoli-filter": { + "name": "broccoli-filter", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-kitchen-sink-helpers", + "broccoli-plugin", + "walk-sync" + ], + "effects": [ + "broccoli-asset-rev", + "broccoli-asset-rewrite" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-filter" + ], + "fixAvailable": { + "name": "broccoli-asset-rev", + "version": "2.5.0", + "isSemVerMajor": true + } + }, + "broccoli-funnel": { + "name": "broccoli-funnel", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-plugin", + "broccoli-plugin", + "minimatch", + "rimraf", + "walk-sync", + "walk-sync" + ], + "effects": [ + "@embroider/addon-shim", + "broccoli-babel-transpiler", + "broccoli-stew", + "ember-auto-import", + "ember-cli", + "ember-cli-babel", + "ember-cli-preprocess-registry", + "ember-cli-sass" + ], + "range": ">=0.1.7", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-funnel", + "node_modules/@embroider/addon-shim/node_modules/broccoli-funnel", + "node_modules/broccoli-funnel", + "node_modules/broccoli-stew/node_modules/broccoli-funnel", + "node_modules/ember-api-store/node_modules/broccoli-funnel", + "node_modules/ember-auto-import/node_modules/broccoli-funnel", + "node_modules/ember-cli-babel/node_modules/broccoli-funnel", + "node_modules/ember-cli-preprocess-registry/node_modules/broccoli-funnel", + "node_modules/ember-cli-sass/node_modules/broccoli-funnel", + "node_modules/ember-cli/node_modules/broccoli-funnel", + "node_modules/ember-fetch/node_modules/broccoli-funnel", + "vendor/ember-cli-pagination/node_modules/broccoli-funnel", + "vendor/ember-rl-dropdown/node_modules/broccoli-funnel", + "vendor/lacsso/node_modules/broccoli-funnel" + ], + "fixAvailable": false + }, + "broccoli-kitchen-sink-helpers": { + "name": "broccoli-kitchen-sink-helpers", + "severity": "moderate", + "isDirect": false, + "via": [ + "glob" + ], + "effects": [ + "broccoli-filter" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-kitchen-sink-helpers" + ], + "fixAvailable": { + "name": "broccoli-asset-rev", + "version": "2.5.0", + "isSemVerMajor": true + } + }, + "broccoli-merge-trees": { + "name": "broccoli-merge-trees", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-plugin", + "merge-trees" + ], + "effects": [ + "broccoli-babel-transpiler", + "broccoli-stew", + "ember-auto-import", + "ember-cli", + "ember-cli-sass" + ], + "range": ">=0.2.2", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-merge-trees", + "node_modules/broccoli-merge-trees", + "node_modules/broccoli-stew/node_modules/broccoli-merge-trees", + "node_modules/ember-cli-sass/node_modules/broccoli-merge-trees" + ], + "fixAvailable": false + }, + "broccoli-persistent-filter": { + "name": "broccoli-persistent-filter", + "severity": "moderate", + "isDirect": false, + "via": [ + "async-disk-cache", + "broccoli-plugin", + "rimraf", + "sync-disk-cache", + "walk-sync" + ], + "effects": [ + "broccoli-asset-rev", + "broccoli-babel-transpiler", + "broccoli-stew", + "ember-cli-htmlbars" + ], + "range": ">=1.0.0", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter", + "node_modules/broccoli-babel-transpiler/node_modules/broccoli-persistent-filter", + "node_modules/broccoli-persistent-filter", + "node_modules/broccoli-stew/node_modules/broccoli-persistent-filter", + "node_modules/ember-cli-htmlbars/node_modules/broccoli-persistent-filter" + ], + "fixAvailable": false + }, + "broccoli-plugin": { + "name": "broccoli-plugin", + "severity": "moderate", + "isDirect": true, + "via": [ + "fs-merger", + "rimraf" + ], + "effects": [ + "broccoli-caching-writer", + "broccoli-concat", + "broccoli-config-replace", + "broccoli-debug", + "broccoli-file-creator", + "broccoli-filter", + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-persistent-filter", + "broccoli-stew", + "broccoli-terser-sourcemap", + "ember-auto-import", + "ember-cli-htmlbars" + ], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-plugin", + "node_modules/@embroider/addon-shim/node_modules/broccoli-plugin", + "node_modules/broccoli-babel-transpiler/node_modules/broccoli-plugin", + "node_modules/broccoli-caching-writer/node_modules/broccoli-plugin", + "node_modules/broccoli-concat/node_modules/broccoli-plugin", + "node_modules/broccoli-config-replace/node_modules/broccoli-plugin", + "node_modules/broccoli-debug/node_modules/broccoli-plugin", + "node_modules/broccoli-file-creator/node_modules/broccoli-plugin", + "node_modules/broccoli-filter/node_modules/broccoli-plugin", + "node_modules/broccoli-merge-trees/node_modules/broccoli-plugin", + "node_modules/broccoli-persistent-filter/node_modules/broccoli-plugin", + "node_modules/broccoli-plugin", + "node_modules/broccoli-stew/node_modules/broccoli-funnel/node_modules/broccoli-plugin", + "node_modules/broccoli-stew/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin", + "node_modules/broccoli-stew/node_modules/broccoli-persistent-filter/node_modules/broccoli-plugin", + "node_modules/broccoli-stew/node_modules/broccoli-plugin", + "node_modules/broccoli-terser-sourcemap/node_modules/broccoli-plugin", + "node_modules/ember-api-store/node_modules/broccoli-plugin", + "node_modules/ember-auto-import/node_modules/broccoli-plugin", + "node_modules/ember-cli-babel/node_modules/broccoli-plugin", + "node_modules/ember-cli-htmlbars/node_modules/broccoli-plugin", + "node_modules/ember-cli-preprocess-registry/node_modules/broccoli-plugin", + "node_modules/ember-cli-sass/node_modules/broccoli-plugin", + "node_modules/ember-cli/node_modules/broccoli-plugin", + "node_modules/ember-fetch/node_modules/broccoli-plugin", + "vendor/ember-cli-pagination/node_modules/broccoli-plugin", + "vendor/ember-rl-dropdown/node_modules/broccoli-plugin", + "vendor/lacsso/node_modules/broccoli-plugin" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-sass-source-maps": { + "name": "broccoli-sass-source-maps", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-caching-writer" + ], + "effects": [ + "ember-cli-sass" + ], + "range": ">=1.8.1", + "nodes": [ + "node_modules/broccoli-sass-source-maps" + ], + "fixAvailable": { + "name": "ember-cli-sass", + "version": "5.5.2", + "isSemVerMajor": true + } + }, + "broccoli-stew": { + "name": "broccoli-stew", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-debug", + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-persistent-filter", + "broccoli-plugin", + "minimatch", + "walk-sync" + ], + "effects": [ + "ember-cli", + "ember-cli-typescript" + ], + "range": ">=0.0.3", + "nodes": [ + "node_modules/broccoli-stew" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-string-replace": { + "name": "broccoli-string-replace", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch" + ], + "effects": [ + "ember-cli-babel" + ], + "range": ">=0.1.0", + "nodes": [ + "node_modules/broccoli-string-replace" + ], + "fixAvailable": false + }, + "broccoli-terser-sourcemap": { + "name": "broccoli-terser-sourcemap", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin", + "matcher-collection", + "walk-sync" + ], + "effects": [ + "ember-cli-terser" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-terser-sourcemap" + ], + "fixAvailable": false + }, + "consolidate": { + "name": "consolidate", + "severity": "moderate", + "isDirect": false, + "via": [ + "ejs" + ], + "effects": [ + "testem" + ], + "range": ">=1.0.0", + "nodes": [ + "node_modules/testem/node_modules/consolidate" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "ejs": { + "name": "ejs", + "severity": "moderate", + "isDirect": false, + "via": [ + "jake" + ], + "effects": [ + "@ember/app-blueprint", + "consolidate" + ], + "range": "3.1.2 - 4.0.1", + "nodes": [ + "node_modules/ejs" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "ember-api-store": { + "name": "ember-api-store", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-cli-babel", + "ember-fetch" + ], + "effects": [], + "range": ">=2.0.0-dev1", + "nodes": [ + "node_modules/ember-api-store" + ], + "fixAvailable": false + }, + "ember-auto-import": { + "name": "ember-auto-import", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-debug", + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-plugin", + "minimatch", + "walk-sync" + ], + "effects": [], + "range": "*", + "nodes": [ + "node_modules/ember-auto-import" + ], + "fixAvailable": { + "name": "ember-auto-import", + "version": "2.6.3", + "isSemVerMajor": true + } + }, + "ember-basic-dropdown": { + "name": "ember-basic-dropdown", + "severity": "moderate", + "isDirect": true, + "via": [ + "@embroider/macros" + ], + "effects": [ + "ember-power-select" + ], + "range": ">=8.1.0", + "nodes": [ + "node_modules/ember-basic-dropdown" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "ember-cli": { + "name": "ember-cli", + "severity": "moderate", + "isDirect": true, + "via": [ + "@ember-tooling/blueprint-model", + "@ember-tooling/classic-build-addon-blueprint", + "@ember-tooling/classic-build-app-blueprint", + "@ember/app-blueprint", + "broccoli", + "broccoli-concat", + "broccoli-config-loader", + "broccoli-config-replace", + "broccoli-debug", + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-stew", + "ember-cli-preprocess-registry", + "glob", + "minimatch", + "quick-temp", + "testem", + "tree-sync", + "walk-sync" + ], + "effects": [], + "range": "<=0.0.21 || >=0.0.33", + "nodes": [ + "node_modules/ember-cli" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "ember-cli-babel": { + "name": "ember-cli-babel", + "severity": "moderate", + "isDirect": true, + "via": [ + "babel-plugin-module-resolver", + "broccoli-babel-transpiler", + "broccoli-babel-transpiler", + "broccoli-debug", + "broccoli-funnel", + "broccoli-string-replace", + "fixturify-project", + "rimraf" + ], + "effects": [ + "@ember/legacy-built-in-components", + "ember-api-store", + "ember-fetch" + ], + "range": ">=5.1.1", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/ember-cli-babel", + "node_modules/ember-api-store/node_modules/ember-cli-babel", + "node_modules/ember-cli-babel", + "node_modules/ember-fetch/node_modules/ember-cli-babel", + "vendor/ember-cli-pagination/node_modules/ember-cli-babel", + "vendor/ember-rl-dropdown/node_modules/ember-cli-babel", + "vendor/lacsso/node_modules/ember-cli-babel" + ], + "fixAvailable": false + }, + "ember-cli-htmlbars": { + "name": "ember-cli-htmlbars", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-debug", + "broccoli-persistent-filter", + "broccoli-plugin", + "ember-source", + "walk-sync" + ], + "effects": [ + "@ember/legacy-built-in-components" + ], + "range": ">=2.0.4", + "nodes": [ + "node_modules/ember-cli-htmlbars" + ], + "fixAvailable": { + "name": "ember-cli-htmlbars", + "version": "5.2.0", + "isSemVerMajor": true + } + }, + "ember-cli-preprocess-registry": { + "name": "ember-cli-preprocess-registry", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-funnel" + ], + "effects": [ + "ember-cli" + ], + "range": ">=1.0.1", + "nodes": [ + "node_modules/ember-cli-preprocess-registry" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "ember-cli-sass": { + "name": "ember-cli-sass", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-sass-source-maps" + ], + "effects": [], + "range": ">=5.2.1", + "nodes": [ + "node_modules/ember-cli-sass" + ], + "fixAvailable": { + "name": "ember-cli-sass", + "version": "5.5.2", + "isSemVerMajor": true + } + }, + "ember-cli-terser": { + "name": "ember-cli-terser", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-terser-sourcemap" + ], + "effects": [], + "range": "*", + "nodes": [ + "node_modules/ember-cli-terser" + ], + "fixAvailable": false + }, + "ember-cli-typescript": { + "name": "ember-cli-typescript", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-stew", + "walk-sync" + ], + "effects": [ + "@ember/legacy-built-in-components" + ], + "range": "0.2.0 - 1.5.0 || >=3.1.3", + "nodes": [ + "node_modules/ember-cli-typescript" + ], + "fixAvailable": { + "name": "@ember/legacy-built-in-components", + "version": "0.2.0", + "isSemVerMajor": true + } + }, + "ember-fetch": { + "name": "ember-fetch", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-cli-babel" + ], + "effects": [ + "ember-api-store" + ], + "range": ">=1.3.0", + "nodes": [ + "node_modules/ember-fetch" + ], + "fixAvailable": false + }, + "ember-load-initializers": { + "name": "ember-load-initializers", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-source" + ], + "effects": [], + "range": ">=3.0.0", + "nodes": [ + "node_modules/ember-load-initializers" + ], + "fixAvailable": { + "name": "ember-load-initializers", + "version": "2.1.2", + "isSemVerMajor": true + } + }, + "ember-power-select": { + "name": "ember-power-select", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-basic-dropdown" + ], + "effects": [], + "range": ">=8.2.0", + "nodes": [ + "node_modules/ember-power-select" + ], + "fixAvailable": { + "name": "ember-power-select", + "version": "8.1.0", + "isSemVerMajor": true + } + }, + "ember-source": { + "name": "ember-source", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-file-creator" + ], + "effects": [ + "@ember/legacy-built-in-components", + "ember-cli-htmlbars", + "ember-load-initializers" + ], + "range": ">=3.27.3", + "nodes": [ + "node_modules/ember-source" + ], + "fixAvailable": { + "name": "ember-source", + "version": "3.27.2", + "isSemVerMajor": true + } + }, + "filelist": { + "name": "filelist", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch" + ], + "effects": [ + "jake" + ], + "range": ">=0.0.2", + "nodes": [ + "node_modules/filelist" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "fixturify": { + "name": "fixturify", + "severity": "moderate", + "isDirect": false, + "via": [ + "matcher-collection" + ], + "effects": [ + "fixturify-project" + ], + "range": ">=0.3.4", + "nodes": [ + "node_modules/fixturify" + ], + "fixAvailable": false + }, + "fixturify-project": { + "name": "fixturify-project", + "severity": "moderate", + "isDirect": false, + "via": [ + "fixturify" + ], + "effects": [ + "ember-cli-babel" + ], + "range": "*", + "nodes": [ + "node_modules/fixturify-project" + ], + "fixAvailable": false + }, + "fs-merger": { + "name": "fs-merger", + "severity": "moderate", + "isDirect": false, + "via": [ + "walk-sync" + ], + "effects": [ + "broccoli-plugin" + ], + "range": ">=3.2.0", + "nodes": [ + "node_modules/fs-merger" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "fs-updater": { + "name": "fs-updater", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf" + ], + "effects": [ + "merge-trees" + ], + "range": "*", + "nodes": [ + "node_modules/fs-updater" + ], + "fixAvailable": false + }, + "glob": { + "name": "glob", + "severity": "moderate", + "isDirect": true, + "via": [ + { + "source": 1244013, + "name": "glob", + "dependency": "glob", + "title": "Glob: AbortSignal cancellation bypass allows post-timeout filesystem traversal", + "url": "https://github.com/advisories/GHSA-3g3m-2fjr-6pw4", + "severity": "moderate", + "cwe": [ + "CWE-400" + ], + "cvss": { + "score": 0, + "vectorString": null + }, + "range": ">=9.0.0 <=14.0.1" + }, + { + "source": "9HFJ6WR6SorMNitST2d41WofDl8v7LE1wctTs9xM/s7BTeJlQPbUd955/7wq8333IGldXab+epFSX7L3eKgo3Q==", + "name": "glob", + "dependency": "glob", + "title": "Glob: AbortSignal cancellation bypass allows post-timeout filesystem traversal", + "url": "https://github.com/advisories/GHSA-3g3m-2fjr-6pw4", + "severity": "moderate", + "cwe": [ + "CWE-400" + ], + "cvss": { + "score": 0, + "vectorString": null + }, + "range": "*" + }, + "minimatch" + ], + "effects": [ + "babel-plugin-module-resolver", + "broccoli-kitchen-sink-helpers", + "ember-cli", + "rimraf", + "testem", + "yamljs" + ], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/glob", + "node_modules/@embroider/addon-shim/node_modules/glob", + "node_modules/async-disk-cache/node_modules/glob", + "node_modules/babel-plugin-module-resolver/node_modules/glob", + "node_modules/broccoli-babel-transpiler/node_modules/glob", + "node_modules/broccoli-caching-writer/node_modules/glob", + "node_modules/broccoli-concat/node_modules/glob", + "node_modules/broccoli-config-replace/node_modules/glob", + "node_modules/broccoli-debug/node_modules/glob", + "node_modules/broccoli-file-creator/node_modules/glob", + "node_modules/broccoli-filter/node_modules/glob", + "node_modules/broccoli-kitchen-sink-helpers/node_modules/glob", + "node_modules/broccoli-merge-trees/node_modules/glob", + "node_modules/broccoli-persistent-filter/node_modules/glob", + "node_modules/broccoli-stew/node_modules/glob", + "node_modules/broccoli-terser-sourcemap/node_modules/glob", + "node_modules/ember-api-store/node_modules/glob", + "node_modules/ember-auto-import/node_modules/glob", + "node_modules/ember-cli-babel/node_modules/glob", + "node_modules/ember-cli-htmlbars/node_modules/glob", + "node_modules/ember-cli-preprocess-registry/node_modules/glob", + "node_modules/ember-cli-sass/node_modules/glob", + "node_modules/ember-cli/node_modules/rimraf/node_modules/glob", + "node_modules/ember-fetch/node_modules/glob", + "node_modules/fs-updater/node_modules/glob", + "node_modules/glob", + "node_modules/glob-real", + "node_modules/quick-temp/node_modules/glob", + "node_modules/sync-disk-cache/node_modules/glob", + "node_modules/yamljs/node_modules/glob", + "vendor/ember-cli-pagination/node_modules/glob", + "vendor/ember-rl-dropdown/node_modules/glob", + "vendor/lacsso/node_modules/glob" + ], + "fixAvailable": false + }, + "jake": { + "name": "jake", + "severity": "moderate", + "isDirect": false, + "via": [ + "filelist" + ], + "effects": [ + "ejs" + ], + "range": ">=10.6.1", + "nodes": [ + "node_modules/jake" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "matcher-collection": { + "name": "matcher-collection", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch" + ], + "effects": [ + "broccoli-terser-sourcemap", + "fixturify", + "walk-sync" + ], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/matcher-collection", + "node_modules/broccoli-stew/node_modules/matcher-collection", + "node_modules/ember-cli/node_modules/tree-sync/node_modules/matcher-collection", + "node_modules/matcher-collection", + "node_modules/walk-sync/node_modules/matcher-collection" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "merge-trees": { + "name": "merge-trees", + "severity": "moderate", + "isDirect": false, + "via": [ + "fs-updater" + ], + "effects": [ + "broccoli-merge-trees" + ], + "range": ">=2.0.0", + "nodes": [ + "node_modules/merge-trees" + ], + "fixAvailable": false + }, + "minimatch": { + "name": "minimatch", + "severity": "moderate", + "isDirect": false, + "via": [ + { + "source": 1244012, + "name": "minimatch", + "dependency": "minimatch", + "title": "minimatch has potential denial of service via globparts amplification", + "url": "https://github.com/advisories/GHSA-g3hv-75wg-m249", + "severity": "moderate", + "cwe": [ + "CWE-405" + ], + "cvss": { + "score": 0, + "vectorString": null + }, + "range": "<11.0.1" + } + ], + "effects": [ + "@ember-tooling/blueprint-model", + "@embroider/shared-internals", + "broccoli-asset-rev", + "broccoli-funnel", + "broccoli-stew", + "broccoli-string-replace", + "ember-auto-import", + "ember-cli", + "filelist", + "glob", + "matcher-collection", + "testem", + "walk-sync" + ], + "range": "<11.0.1", + "nodes": [ + "node_modules/@ember-tooling/blueprint-model/node_modules/minimatch", + "node_modules/@ember/app-blueprint/node_modules/minimatch", + "node_modules/babel-plugin-module-resolver/node_modules/minimatch", + "node_modules/broccoli-funnel/node_modules/minimatch", + "node_modules/ember-cli-htmlbars/node_modules/walk-sync/node_modules/minimatch", + "node_modules/ember-cli/node_modules/broccoli-funnel/node_modules/minimatch", + "node_modules/ember-cli/node_modules/minimatch", + "node_modules/ember-cli/node_modules/rimraf/node_modules/minimatch", + "node_modules/ember-cli/node_modules/tree-sync/node_modules/minimatch", + "node_modules/filelist/node_modules/minimatch", + "node_modules/glob-real/node_modules/minimatch", + "node_modules/minimatch", + "node_modules/quick-temp/node_modules/minimatch", + "node_modules/testem/node_modules/minimatch" + ], + "fixAvailable": false + }, + "quick-temp": { + "name": "quick-temp", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf" + ], + "effects": [ + "@ember-tooling/blueprint-model", + "ember-cli" + ], + "range": ">=0.1.9", + "nodes": [ + "node_modules/quick-temp" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "rimraf": { + "name": "rimraf", + "severity": "moderate", + "isDirect": true, + "via": [ + { + "source": "BHZwZR31ewGtqcFzaSO/wyGjELErgaq4dQmVrnbnUKgAjOcAiuI4v+e5/zDcW8SO/+YvoZnsNvDN2poKt4viZw==", + "name": "rimraf", + "dependency": "rimraf", + "title": "Depends on vulnerable versions of glob", + "url": null, + "severity": "moderate", + "cwe": [ + "CWE-400" + ], + "cvss": { + "score": 0, + "vectorString": null + }, + "range": "*" + }, + "glob", + "glob" + ], + "effects": [ + "async-disk-cache", + "broccoli", + "broccoli-funnel", + "broccoli-persistent-filter", + "broccoli-plugin", + "ember-cli-babel", + "fs-updater", + "quick-temp", + "sync-disk-cache", + "testem" + ], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-funnel/node_modules/rimraf", + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter/node_modules/rimraf", + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-plugin/node_modules/rimraf", + "node_modules/@ember/legacy-built-in-components/node_modules/rimraf", + "node_modules/@ember/legacy-built-in-components/node_modules/sync-disk-cache/node_modules/rimraf", + "node_modules/@embroider/addon-shim/node_modules/rimraf", + "node_modules/async-disk-cache/node_modules/rimraf", + "node_modules/broccoli-babel-transpiler/node_modules/rimraf", + "node_modules/broccoli-caching-writer/node_modules/rimraf", + "node_modules/broccoli-concat/node_modules/rimraf", + "node_modules/broccoli-config-replace/node_modules/rimraf", + "node_modules/broccoli-debug/node_modules/rimraf", + "node_modules/broccoli-file-creator/node_modules/rimraf", + "node_modules/broccoli-filter/node_modules/rimraf", + "node_modules/broccoli-merge-trees/node_modules/rimraf", + "node_modules/broccoli-persistent-filter/node_modules/rimraf", + "node_modules/broccoli-stew/node_modules/rimraf", + "node_modules/broccoli-terser-sourcemap/node_modules/rimraf", + "node_modules/ember-api-store/node_modules/rimraf", + "node_modules/ember-auto-import/node_modules/rimraf", + "node_modules/ember-cli-babel/node_modules/rimraf", + "node_modules/ember-cli-htmlbars/node_modules/rimraf", + "node_modules/ember-cli-preprocess-registry/node_modules/rimraf", + "node_modules/ember-cli-sass/node_modules/rimraf", + "node_modules/ember-cli/node_modules/rimraf", + "node_modules/ember-fetch/node_modules/rimraf", + "node_modules/fs-updater/node_modules/rimraf", + "node_modules/quick-temp/node_modules/rimraf", + "node_modules/rimraf", + "node_modules/rimraf-real", + "node_modules/sync-disk-cache/node_modules/rimraf", + "vendor/ember-cli-pagination/node_modules/rimraf", + "vendor/ember-rl-dropdown/node_modules/rimraf", + "vendor/lacsso/node_modules/rimraf" + ], + "fixAvailable": false + }, + "sync-disk-cache": { + "name": "sync-disk-cache", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf" + ], + "effects": [ + "broccoli-persistent-filter" + ], + "range": ">=2.0.0", + "nodes": [ + "node_modules/sync-disk-cache" + ], + "fixAvailable": false + }, + "testem": { + "name": "testem", + "severity": "moderate", + "isDirect": false, + "via": [ + "consolidate", + "glob", + "minimatch", + "rimraf" + ], + "effects": [ + "ember-cli" + ], + "range": "3.19.0 - 3.21.5", + "nodes": [ + "node_modules/testem" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "tree-sync": { + "name": "tree-sync", + "severity": "moderate", + "isDirect": false, + "via": [ + "walk-sync" + ], + "effects": [ + "broccoli", + "broccoli-debug", + "ember-cli" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli/node_modules/tree-sync", + "node_modules/ember-cli/node_modules/tree-sync", + "node_modules/tree-sync" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "walk-sync": { + "name": "walk-sync", + "severity": "moderate", + "isDirect": false, + "via": [ + "matcher-collection", + "minimatch" + ], + "effects": [ + "@ember-tooling/blueprint-model", + "@ember-tooling/classic-build-addon-blueprint", + "@ember/app-blueprint", + "broccoli-caching-writer", + "broccoli-filter", + "broccoli-funnel", + "broccoli-persistent-filter", + "broccoli-stew", + "broccoli-terser-sourcemap", + "ember-auto-import", + "ember-cli", + "ember-cli-htmlbars", + "ember-cli-typescript", + "fs-merger", + "tree-sync" + ], + "range": ">=0.2.0", + "nodes": [ + "node_modules/@ember-tooling/blueprint-model/node_modules/walk-sync", + "node_modules/@ember-tooling/classic-build-addon-blueprint/node_modules/walk-sync", + "node_modules/@ember/app-blueprint/node_modules/walk-sync", + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter/node_modules/walk-sync", + "node_modules/@embroider/addon-shim/node_modules/walk-sync", + "node_modules/broccoli-funnel/node_modules/walk-sync", + "node_modules/broccoli-stew/node_modules/broccoli-funnel/node_modules/walk-sync", + "node_modules/broccoli-stew/node_modules/walk-sync", + "node_modules/broccoli-terser-sourcemap/node_modules/walk-sync", + "node_modules/ember-api-store/node_modules/walk-sync", + "node_modules/ember-auto-import/node_modules/broccoli-funnel/node_modules/walk-sync", + "node_modules/ember-auto-import/node_modules/walk-sync", + "node_modules/ember-cli-babel/node_modules/walk-sync", + "node_modules/ember-cli-htmlbars/node_modules/walk-sync", + "node_modules/ember-cli-preprocess-registry/node_modules/walk-sync", + "node_modules/ember-cli-typescript/node_modules/walk-sync", + "node_modules/ember-cli/node_modules/broccoli-funnel/node_modules/walk-sync", + "node_modules/ember-cli/node_modules/tree-sync/node_modules/walk-sync", + "node_modules/ember-cli/node_modules/walk-sync", + "node_modules/ember-fetch/node_modules/walk-sync", + "node_modules/fs-merger/node_modules/walk-sync", + "node_modules/walk-sync", + "vendor/ember-cli-pagination/node_modules/walk-sync", + "vendor/ember-rl-dropdown/node_modules/walk-sync", + "vendor/lacsso/node_modules/walk-sync" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "yamljs": { + "name": "yamljs", + "severity": "moderate", + "isDirect": true, + "via": [ + "glob" + ], + "effects": [], + "range": ">=0.1.1", + "nodes": [ + "node_modules/yamljs" + ], + "fixAvailable": { + "name": "yamljs", + "version": "0.1.0", + "isSemVerMajor": true + } + } + }, + "metadata": { + "vulnerabilities": { + "info": 0, + "low": 0, + "moderate": 63, + "high": 0, + "critical": 0, + "total": 63 + }, + "dependencies": { + "prod": 8, + "dev": 1456, + "optional": 18, + "peer": 1, + "peerOptional": 0, + "total": 1479 + } + } +} diff --git a/scripts/fixtures/npm-audit/npm12-before-follow-redirects.json b/scripts/fixtures/npm-audit/npm12-before-follow-redirects.json new file mode 100644 index 0000000000..8bcefd61cc --- /dev/null +++ b/scripts/fixtures/npm-audit/npm12-before-follow-redirects.json @@ -0,0 +1,1632 @@ +{ + "auditReportVersion": 2, + "vulnerabilities": { + "@ember-tooling/blueprint-model": { + "name": "@ember-tooling/blueprint-model", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch", + "quick-temp", + "walk-sync" + ], + "effects": [ + "@ember-tooling/classic-build-addon-blueprint", + "@ember-tooling/classic-build-app-blueprint", + "ember-cli" + ], + "range": ">=0.6.2", + "nodes": [ + "node_modules/@ember-tooling/blueprint-model" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "@ember-tooling/classic-build-addon-blueprint": { + "name": "@ember-tooling/classic-build-addon-blueprint", + "severity": "moderate", + "isDirect": false, + "via": [ + "@ember-tooling/blueprint-model", + "walk-sync" + ], + "effects": [ + "ember-cli" + ], + "range": ">=6.7.0-alpha.3", + "nodes": [ + "node_modules/@ember-tooling/classic-build-addon-blueprint" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "@ember-tooling/classic-build-app-blueprint": { + "name": "@ember-tooling/classic-build-app-blueprint", + "severity": "moderate", + "isDirect": false, + "via": [ + "@ember-tooling/blueprint-model" + ], + "effects": [ + "ember-cli" + ], + "range": ">=7.1.0-alpha.1", + "nodes": [ + "node_modules/@ember-tooling/classic-build-app-blueprint" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "@ember/app-blueprint": { + "name": "@ember/app-blueprint", + "severity": "moderate", + "isDirect": false, + "via": [ + "ejs", + "walk-sync" + ], + "effects": [ + "ember-cli" + ], + "range": ">=0.1.0", + "nodes": [ + "node_modules/@ember/app-blueprint" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "@ember/legacy-built-in-components": { + "name": "@ember/legacy-built-in-components", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-cli-babel", + "ember-cli-htmlbars", + "ember-cli-typescript" + ], + "effects": [], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components" + ], + "fixAvailable": false + }, + "@embroider/addon-shim": { + "name": "@embroider/addon-shim", + "severity": "moderate", + "isDirect": false, + "via": [ + "@embroider/shared-internals", + "broccoli-funnel" + ], + "effects": [], + "range": "1.8.4-unstable.00ec2e7 - 1.10.3 || >=2.0.0-alpha.0", + "nodes": [ + "node_modules/@embroider/addon-shim" + ], + "fixAvailable": true + }, + "@embroider/macros": { + "name": "@embroider/macros", + "severity": "moderate", + "isDirect": false, + "via": [ + "@embroider/shared-internals", + "ember-cli-babel" + ], + "effects": [ + "ember-basic-dropdown" + ], + "range": ">=0.20.0", + "nodes": [ + "node_modules/@embroider/macros" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "@embroider/shared-internals": { + "name": "@embroider/shared-internals", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch" + ], + "effects": [ + "@embroider/addon-shim", + "@embroider/macros" + ], + "range": ">=2.5.3-unstable.11f2c70", + "nodes": [ + "node_modules/@embroider/shared-internals", + "node_modules/ember-auto-import/node_modules/@embroider/shared-internals" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "async-disk-cache": { + "name": "async-disk-cache", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf" + ], + "effects": [ + "broccoli-persistent-filter" + ], + "range": ">=1.0.8", + "nodes": [ + "node_modules/async-disk-cache", + "node_modules/broccoli-babel-transpiler/node_modules/async-disk-cache", + "node_modules/ember-cli-htmlbars/node_modules/async-disk-cache" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "babel-plugin-module-resolver": { + "name": "babel-plugin-module-resolver", + "severity": "moderate", + "isDirect": false, + "via": [ + "glob", + "glob" + ], + "effects": [ + "ember-cli-babel" + ], + "range": ">=2.2.0", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/babel-plugin-module-resolver", + "node_modules/babel-plugin-module-resolver" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "broccoli": { + "name": "broccoli", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf", + "tree-sync" + ], + "effects": [ + "ember-cli" + ], + "range": ">=2.0.0-beta.1", + "nodes": [ + "node_modules/broccoli" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-asset-rev": { + "name": "broccoli-asset-rev", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-asset-rewrite", + "broccoli-filter", + "broccoli-persistent-filter", + "minimatch" + ], + "effects": [], + "range": "*", + "nodes": [ + "node_modules/broccoli-asset-rev" + ], + "fixAvailable": { + "name": "broccoli-asset-rev", + "version": "2.5.0", + "isSemVerMajor": true + } + }, + "broccoli-asset-rewrite": { + "name": "broccoli-asset-rewrite", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-filter" + ], + "effects": [ + "broccoli-asset-rev" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-asset-rewrite" + ], + "fixAvailable": { + "name": "broccoli-asset-rev", + "version": "2.5.0", + "isSemVerMajor": true + } + }, + "broccoli-babel-transpiler": { + "name": "broccoli-babel-transpiler", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-persistent-filter" + ], + "effects": [ + "ember-cli-babel" + ], + "range": ">=5.3.0", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-babel-transpiler", + "node_modules/broccoli-babel-transpiler" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "broccoli-caching-writer": { + "name": "broccoli-caching-writer", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin", + "walk-sync" + ], + "effects": [ + "broccoli-config-loader", + "broccoli-sass-source-maps" + ], + "range": ">=2.0.0", + "nodes": [ + "node_modules/broccoli-caching-writer" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-concat": { + "name": "broccoli-concat", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-debug", + "broccoli-plugin" + ], + "effects": [ + "ember-cli" + ], + "range": ">=3.1.0", + "nodes": [ + "node_modules/broccoli-concat" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-config-loader": { + "name": "broccoli-config-loader", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-caching-writer" + ], + "effects": [ + "ember-cli" + ], + "range": ">=1.0.1", + "nodes": [ + "node_modules/broccoli-config-loader" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-config-replace": { + "name": "broccoli-config-replace", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin" + ], + "effects": [ + "ember-cli" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-config-replace" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "broccoli-debug": { + "name": "broccoli-debug", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin", + "tree-sync" + ], + "effects": [ + "broccoli-concat", + "broccoli-stew", + "ember-auto-import", + "ember-cli", + "ember-cli-babel", + "ember-cli-htmlbars" + ], + "range": ">=0.6.0", + "nodes": [ + "node_modules/broccoli-debug" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "broccoli-file-creator": { + "name": "broccoli-file-creator", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin" + ], + "effects": [ + "ember-source" + ], + "range": ">=1.0.0", + "nodes": [ + "node_modules/broccoli-file-creator" + ], + "fixAvailable": { + "name": "ember-source", + "version": "7.4.0", + "isSemVerMajor": false + } + }, + "broccoli-filter": { + "name": "broccoli-filter", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-kitchen-sink-helpers", + "broccoli-plugin", + "walk-sync" + ], + "effects": [ + "broccoli-asset-rev", + "broccoli-asset-rewrite" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-filter" + ], + "fixAvailable": { + "name": "broccoli-asset-rev", + "version": "2.5.0", + "isSemVerMajor": true + } + }, + "broccoli-funnel": { + "name": "broccoli-funnel", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-plugin", + "broccoli-plugin", + "minimatch", + "rimraf", + "walk-sync", + "walk-sync" + ], + "effects": [ + "@embroider/addon-shim", + "broccoli-babel-transpiler", + "broccoli-stew", + "ember-auto-import", + "ember-cli", + "ember-cli-babel", + "ember-cli-preprocess-registry", + "ember-cli-sass" + ], + "range": ">=0.1.7", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-funnel", + "node_modules/@embroider/addon-shim/node_modules/broccoli-funnel", + "node_modules/broccoli-funnel", + "node_modules/broccoli-stew/node_modules/broccoli-funnel", + "node_modules/ember-api-store/node_modules/broccoli-funnel", + "node_modules/ember-auto-import/node_modules/broccoli-funnel", + "node_modules/ember-cli-babel/node_modules/broccoli-funnel", + "node_modules/ember-cli-preprocess-registry/node_modules/broccoli-funnel", + "node_modules/ember-cli-sass/node_modules/broccoli-funnel", + "node_modules/ember-cli/node_modules/broccoli-funnel", + "node_modules/ember-fetch/node_modules/broccoli-funnel", + "vendor/ember-cli-pagination/node_modules/broccoli-funnel", + "vendor/ember-rl-dropdown/node_modules/broccoli-funnel", + "vendor/lacsso/node_modules/broccoli-funnel" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "broccoli-kitchen-sink-helpers": { + "name": "broccoli-kitchen-sink-helpers", + "severity": "moderate", + "isDirect": false, + "via": [ + "glob" + ], + "effects": [ + "broccoli-filter" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-kitchen-sink-helpers" + ], + "fixAvailable": { + "name": "broccoli-asset-rev", + "version": "2.5.0", + "isSemVerMajor": true + } + }, + "broccoli-merge-trees": { + "name": "broccoli-merge-trees", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-plugin", + "merge-trees" + ], + "effects": [ + "broccoli-babel-transpiler", + "broccoli-stew", + "ember-auto-import", + "ember-cli", + "ember-cli-sass" + ], + "range": ">=0.2.2", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-merge-trees", + "node_modules/broccoli-merge-trees", + "node_modules/broccoli-stew/node_modules/broccoli-merge-trees", + "node_modules/ember-cli-sass/node_modules/broccoli-merge-trees" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "broccoli-persistent-filter": { + "name": "broccoli-persistent-filter", + "severity": "moderate", + "isDirect": false, + "via": [ + "async-disk-cache", + "broccoli-plugin", + "rimraf", + "sync-disk-cache", + "walk-sync" + ], + "effects": [ + "broccoli-asset-rev", + "broccoli-babel-transpiler", + "broccoli-stew", + "ember-cli-htmlbars" + ], + "range": ">=1.0.0", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter", + "node_modules/broccoli-babel-transpiler/node_modules/broccoli-persistent-filter", + "node_modules/broccoli-persistent-filter", + "node_modules/broccoli-stew/node_modules/broccoli-persistent-filter", + "node_modules/ember-cli-htmlbars/node_modules/broccoli-persistent-filter" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "broccoli-plugin": { + "name": "broccoli-plugin", + "severity": "moderate", + "isDirect": true, + "via": [ + "fs-merger", + "rimraf" + ], + "effects": [ + "broccoli-caching-writer", + "broccoli-concat", + "broccoli-config-replace", + "broccoli-debug", + "broccoli-file-creator", + "broccoli-filter", + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-persistent-filter", + "broccoli-stew", + "broccoli-terser-sourcemap", + "ember-auto-import", + "ember-cli-htmlbars" + ], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-plugin", + "node_modules/@embroider/addon-shim/node_modules/broccoli-plugin", + "node_modules/broccoli-babel-transpiler/node_modules/broccoli-plugin", + "node_modules/broccoli-caching-writer/node_modules/broccoli-plugin", + "node_modules/broccoli-concat/node_modules/broccoli-plugin", + "node_modules/broccoli-config-replace/node_modules/broccoli-plugin", + "node_modules/broccoli-debug/node_modules/broccoli-plugin", + "node_modules/broccoli-file-creator/node_modules/broccoli-plugin", + "node_modules/broccoli-filter/node_modules/broccoli-plugin", + "node_modules/broccoli-merge-trees/node_modules/broccoli-plugin", + "node_modules/broccoli-persistent-filter/node_modules/broccoli-plugin", + "node_modules/broccoli-plugin", + "node_modules/broccoli-stew/node_modules/broccoli-funnel/node_modules/broccoli-plugin", + "node_modules/broccoli-stew/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin", + "node_modules/broccoli-stew/node_modules/broccoli-persistent-filter/node_modules/broccoli-plugin", + "node_modules/broccoli-stew/node_modules/broccoli-plugin", + "node_modules/broccoli-terser-sourcemap/node_modules/broccoli-plugin", + "node_modules/ember-api-store/node_modules/broccoli-plugin", + "node_modules/ember-auto-import/node_modules/broccoli-plugin", + "node_modules/ember-cli-babel/node_modules/broccoli-plugin", + "node_modules/ember-cli-htmlbars/node_modules/broccoli-plugin", + "node_modules/ember-cli-preprocess-registry/node_modules/broccoli-plugin", + "node_modules/ember-cli-sass/node_modules/broccoli-plugin", + "node_modules/ember-cli/node_modules/broccoli-plugin", + "node_modules/ember-fetch/node_modules/broccoli-plugin", + "vendor/ember-cli-pagination/node_modules/broccoli-plugin", + "vendor/ember-rl-dropdown/node_modules/broccoli-plugin", + "vendor/lacsso/node_modules/broccoli-plugin" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "broccoli-sass-source-maps": { + "name": "broccoli-sass-source-maps", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-caching-writer" + ], + "effects": [ + "ember-cli-sass" + ], + "range": ">=1.8.1", + "nodes": [ + "node_modules/broccoli-sass-source-maps" + ], + "fixAvailable": { + "name": "ember-cli-sass", + "version": "5.5.2", + "isSemVerMajor": true + } + }, + "broccoli-stew": { + "name": "broccoli-stew", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-debug", + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-persistent-filter", + "broccoli-plugin", + "minimatch", + "walk-sync" + ], + "effects": [ + "ember-cli", + "ember-cli-typescript" + ], + "range": ">=0.0.3", + "nodes": [ + "node_modules/broccoli-stew" + ], + "fixAvailable": false + }, + "broccoli-string-replace": { + "name": "broccoli-string-replace", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch" + ], + "effects": [ + "ember-cli-babel" + ], + "range": ">=0.1.0", + "nodes": [ + "node_modules/broccoli-string-replace" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "broccoli-terser-sourcemap": { + "name": "broccoli-terser-sourcemap", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-plugin", + "matcher-collection", + "walk-sync" + ], + "effects": [ + "ember-cli-terser" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli-terser-sourcemap" + ], + "fixAvailable": false + }, + "consolidate": { + "name": "consolidate", + "severity": "moderate", + "isDirect": false, + "via": [ + "ejs" + ], + "effects": [ + "testem" + ], + "range": ">=1.0.0", + "nodes": [ + "node_modules/testem/node_modules/consolidate" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "ejs": { + "name": "ejs", + "severity": "moderate", + "isDirect": false, + "via": [ + "jake" + ], + "effects": [ + "@ember/app-blueprint", + "consolidate" + ], + "range": "3.1.2 - 4.0.1", + "nodes": [ + "node_modules/ejs" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "ember-api-store": { + "name": "ember-api-store", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-cli-babel", + "ember-fetch" + ], + "effects": [], + "range": ">=2.0.0-dev1", + "nodes": [ + "node_modules/ember-api-store" + ], + "fixAvailable": false + }, + "ember-auto-import": { + "name": "ember-auto-import", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-debug", + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-plugin", + "minimatch", + "walk-sync" + ], + "effects": [], + "range": "*", + "nodes": [ + "node_modules/ember-auto-import" + ], + "fixAvailable": { + "name": "ember-auto-import", + "version": "2.6.3", + "isSemVerMajor": true + } + }, + "ember-basic-dropdown": { + "name": "ember-basic-dropdown", + "severity": "moderate", + "isDirect": true, + "via": [ + "@embroider/macros" + ], + "effects": [ + "ember-power-select" + ], + "range": ">=8.1.0", + "nodes": [ + "node_modules/ember-basic-dropdown" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "ember-cli": { + "name": "ember-cli", + "severity": "moderate", + "isDirect": true, + "via": [ + "@ember-tooling/blueprint-model", + "@ember-tooling/classic-build-addon-blueprint", + "@ember-tooling/classic-build-app-blueprint", + "@ember/app-blueprint", + "broccoli", + "broccoli-concat", + "broccoli-config-loader", + "broccoli-config-replace", + "broccoli-debug", + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-stew", + "ember-cli-preprocess-registry", + "glob", + "minimatch", + "quick-temp", + "testem", + "tree-sync", + "walk-sync" + ], + "effects": [], + "range": "<=0.0.21 || >=0.0.33", + "nodes": [ + "node_modules/ember-cli" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "ember-cli-babel": { + "name": "ember-cli-babel", + "severity": "moderate", + "isDirect": true, + "via": [ + "babel-plugin-module-resolver", + "broccoli-babel-transpiler", + "broccoli-babel-transpiler", + "broccoli-debug", + "broccoli-funnel", + "broccoli-string-replace", + "fixturify-project", + "rimraf" + ], + "effects": [ + "@ember/legacy-built-in-components", + "@embroider/macros", + "ember-api-store", + "ember-fetch", + "ember-source" + ], + "range": ">=5.1.1", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/ember-cli-babel", + "node_modules/ember-api-store/node_modules/ember-cli-babel", + "node_modules/ember-cli-babel", + "node_modules/ember-fetch/node_modules/ember-cli-babel", + "vendor/ember-cli-pagination/node_modules/ember-cli-babel", + "vendor/ember-rl-dropdown/node_modules/ember-cli-babel", + "vendor/lacsso/node_modules/ember-cli-babel" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "ember-cli-htmlbars": { + "name": "ember-cli-htmlbars", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-debug", + "broccoli-persistent-filter", + "broccoli-plugin", + "walk-sync" + ], + "effects": [ + "@ember/legacy-built-in-components" + ], + "range": ">=2.0.4", + "nodes": [ + "node_modules/ember-cli-htmlbars" + ], + "fixAvailable": false + }, + "ember-cli-preprocess-registry": { + "name": "ember-cli-preprocess-registry", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-funnel" + ], + "effects": [ + "ember-cli" + ], + "range": ">=1.0.1", + "nodes": [ + "node_modules/ember-cli-preprocess-registry" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "ember-cli-sass": { + "name": "ember-cli-sass", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-funnel", + "broccoli-merge-trees", + "broccoli-sass-source-maps" + ], + "effects": [], + "range": ">=5.2.1", + "nodes": [ + "node_modules/ember-cli-sass" + ], + "fixAvailable": { + "name": "ember-cli-sass", + "version": "5.5.2", + "isSemVerMajor": true + } + }, + "ember-cli-terser": { + "name": "ember-cli-terser", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-terser-sourcemap" + ], + "effects": [], + "range": "*", + "nodes": [ + "node_modules/ember-cli-terser" + ], + "fixAvailable": false + }, + "ember-cli-typescript": { + "name": "ember-cli-typescript", + "severity": "moderate", + "isDirect": false, + "via": [ + "broccoli-stew", + "walk-sync" + ], + "effects": [ + "@ember/legacy-built-in-components" + ], + "range": "0.2.0 - 1.5.0 || >=3.1.3", + "nodes": [ + "node_modules/ember-cli-typescript" + ], + "fixAvailable": false + }, + "ember-fetch": { + "name": "ember-fetch", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-cli-babel" + ], + "effects": [ + "ember-api-store" + ], + "range": ">=1.3.0", + "nodes": [ + "node_modules/ember-fetch" + ], + "fixAvailable": false + }, + "ember-power-select": { + "name": "ember-power-select", + "severity": "moderate", + "isDirect": true, + "via": [ + "ember-basic-dropdown" + ], + "effects": [], + "range": ">=8.2.0", + "nodes": [ + "node_modules/ember-power-select" + ], + "fixAvailable": { + "name": "ember-power-select", + "version": "8.1.0", + "isSemVerMajor": true + } + }, + "ember-source": { + "name": "ember-source", + "severity": "moderate", + "isDirect": true, + "via": [ + "broccoli-file-creator", + "ember-cli-babel" + ], + "effects": [], + "range": ">=3.6.0-beta.1", + "nodes": [ + "node_modules/ember-source" + ], + "fixAvailable": { + "name": "ember-source", + "version": "7.4.0", + "isSemVerMajor": false + } + }, + "filelist": { + "name": "filelist", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch" + ], + "effects": [ + "jake" + ], + "range": ">=0.0.2", + "nodes": [ + "node_modules/filelist" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "fixturify": { + "name": "fixturify", + "severity": "moderate", + "isDirect": false, + "via": [ + "matcher-collection" + ], + "effects": [ + "fixturify-project" + ], + "range": ">=0.3.4", + "nodes": [ + "node_modules/fixturify" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "fixturify-project": { + "name": "fixturify-project", + "severity": "moderate", + "isDirect": false, + "via": [ + "fixturify" + ], + "effects": [ + "ember-cli-babel" + ], + "range": "*", + "nodes": [ + "node_modules/fixturify-project" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "follow-redirects": { + "name": "follow-redirects", + "severity": "high", + "isDirect": false, + "via": [ + { + "source": 1244003, + "name": "follow-redirects", + "dependency": "follow-redirects", + "title": "follow-redirects: Cross-realm sensitiveHeaders arrays are discarded and custom credentials can follow redirects", + "url": "https://github.com/advisories/GHSA-mrwp-f3q8-3g9p", + "severity": "high", + "cwe": [ + "CWE-201" + ], + "cvss": { + "score": 5.9, + "vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N" + }, + "range": ">=1.16.0 <=1.16.1" + } + ], + "effects": [], + "range": "1.16.0 - 1.16.1", + "nodes": [ + "node_modules/follow-redirects" + ], + "fixAvailable": true + }, + "fs-merger": { + "name": "fs-merger", + "severity": "moderate", + "isDirect": false, + "via": [ + "walk-sync" + ], + "effects": [ + "broccoli-plugin" + ], + "range": ">=3.2.0", + "nodes": [ + "node_modules/fs-merger" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "fs-updater": { + "name": "fs-updater", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf" + ], + "effects": [ + "merge-trees" + ], + "range": "*", + "nodes": [ + "node_modules/fs-updater" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "glob": { + "name": "glob", + "severity": "moderate", + "isDirect": true, + "via": [ + { + "source": 1244013, + "name": "glob", + "dependency": "glob", + "title": "Glob: AbortSignal cancellation bypass allows post-timeout filesystem traversal", + "url": "https://github.com/advisories/GHSA-3g3m-2fjr-6pw4", + "severity": "moderate", + "cwe": [ + "CWE-400" + ], + "cvss": { + "score": 0, + "vectorString": null + }, + "range": ">=9.0.0 <=14.0.1" + }, + { + "source": "9HFJ6WR6SorMNitST2d41WofDl8v7LE1wctTs9xM/s7BTeJlQPbUd955/7wq8333IGldXab+epFSX7L3eKgo3Q==", + "name": "glob", + "dependency": "glob", + "title": "Glob: AbortSignal cancellation bypass allows post-timeout filesystem traversal", + "url": "https://github.com/advisories/GHSA-3g3m-2fjr-6pw4", + "severity": "moderate", + "cwe": [ + "CWE-400" + ], + "cvss": { + "score": 0, + "vectorString": null + }, + "range": "*" + }, + "minimatch" + ], + "effects": [ + "babel-plugin-module-resolver", + "broccoli-kitchen-sink-helpers", + "ember-cli", + "rimraf", + "testem", + "yamljs" + ], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/glob", + "node_modules/@embroider/addon-shim/node_modules/glob", + "node_modules/async-disk-cache/node_modules/glob", + "node_modules/babel-plugin-module-resolver/node_modules/glob", + "node_modules/broccoli-babel-transpiler/node_modules/glob", + "node_modules/broccoli-caching-writer/node_modules/glob", + "node_modules/broccoli-concat/node_modules/glob", + "node_modules/broccoli-config-replace/node_modules/glob", + "node_modules/broccoli-debug/node_modules/glob", + "node_modules/broccoli-file-creator/node_modules/glob", + "node_modules/broccoli-filter/node_modules/glob", + "node_modules/broccoli-kitchen-sink-helpers/node_modules/glob", + "node_modules/broccoli-merge-trees/node_modules/glob", + "node_modules/broccoli-persistent-filter/node_modules/glob", + "node_modules/broccoli-stew/node_modules/glob", + "node_modules/broccoli-terser-sourcemap/node_modules/glob", + "node_modules/ember-api-store/node_modules/glob", + "node_modules/ember-auto-import/node_modules/glob", + "node_modules/ember-cli-babel/node_modules/glob", + "node_modules/ember-cli-htmlbars/node_modules/glob", + "node_modules/ember-cli-preprocess-registry/node_modules/glob", + "node_modules/ember-cli-sass/node_modules/glob", + "node_modules/ember-cli/node_modules/rimraf/node_modules/glob", + "node_modules/ember-fetch/node_modules/glob", + "node_modules/fs-updater/node_modules/glob", + "node_modules/glob", + "node_modules/glob-real", + "node_modules/quick-temp/node_modules/glob", + "node_modules/sync-disk-cache/node_modules/glob", + "node_modules/yamljs/node_modules/glob", + "vendor/ember-cli-pagination/node_modules/glob", + "vendor/ember-rl-dropdown/node_modules/glob", + "vendor/lacsso/node_modules/glob" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "jake": { + "name": "jake", + "severity": "moderate", + "isDirect": false, + "via": [ + "filelist" + ], + "effects": [ + "ejs" + ], + "range": ">=10.6.1", + "nodes": [ + "node_modules/jake" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "matcher-collection": { + "name": "matcher-collection", + "severity": "moderate", + "isDirect": false, + "via": [ + "minimatch" + ], + "effects": [ + "broccoli-terser-sourcemap", + "fixturify", + "walk-sync" + ], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/matcher-collection", + "node_modules/broccoli-stew/node_modules/matcher-collection", + "node_modules/ember-cli/node_modules/tree-sync/node_modules/matcher-collection", + "node_modules/matcher-collection", + "node_modules/walk-sync/node_modules/matcher-collection" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "merge-trees": { + "name": "merge-trees", + "severity": "moderate", + "isDirect": false, + "via": [ + "fs-updater" + ], + "effects": [ + "broccoli-merge-trees" + ], + "range": ">=2.0.0", + "nodes": [ + "node_modules/merge-trees" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "minimatch": { + "name": "minimatch", + "severity": "moderate", + "isDirect": false, + "via": [ + { + "source": 1244012, + "name": "minimatch", + "dependency": "minimatch", + "title": "minimatch has potential denial of service via globparts amplification", + "url": "https://github.com/advisories/GHSA-g3hv-75wg-m249", + "severity": "moderate", + "cwe": [ + "CWE-405" + ], + "cvss": { + "score": 0, + "vectorString": null + }, + "range": "<11.0.1" + } + ], + "effects": [ + "@ember-tooling/blueprint-model", + "@embroider/shared-internals", + "broccoli-asset-rev", + "broccoli-funnel", + "broccoli-stew", + "broccoli-string-replace", + "ember-auto-import", + "ember-cli", + "filelist", + "glob", + "matcher-collection", + "testem", + "walk-sync" + ], + "range": "<11.0.1", + "nodes": [ + "node_modules/@ember-tooling/blueprint-model/node_modules/minimatch", + "node_modules/@ember/app-blueprint/node_modules/minimatch", + "node_modules/babel-plugin-module-resolver/node_modules/minimatch", + "node_modules/broccoli-funnel/node_modules/minimatch", + "node_modules/ember-cli-htmlbars/node_modules/walk-sync/node_modules/minimatch", + "node_modules/ember-cli/node_modules/broccoli-funnel/node_modules/minimatch", + "node_modules/ember-cli/node_modules/minimatch", + "node_modules/ember-cli/node_modules/rimraf/node_modules/minimatch", + "node_modules/ember-cli/node_modules/tree-sync/node_modules/minimatch", + "node_modules/filelist/node_modules/minimatch", + "node_modules/glob-real/node_modules/minimatch", + "node_modules/minimatch", + "node_modules/quick-temp/node_modules/minimatch", + "node_modules/testem/node_modules/minimatch" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "quick-temp": { + "name": "quick-temp", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf" + ], + "effects": [ + "@ember-tooling/blueprint-model", + "ember-cli" + ], + "range": ">=0.1.9", + "nodes": [ + "node_modules/quick-temp" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "rimraf": { + "name": "rimraf", + "severity": "moderate", + "isDirect": true, + "via": [ + { + "source": "BHZwZR31ewGtqcFzaSO/wyGjELErgaq4dQmVrnbnUKgAjOcAiuI4v+e5/zDcW8SO/+YvoZnsNvDN2poKt4viZw==", + "name": "rimraf", + "dependency": "rimraf", + "title": "Depends on vulnerable versions of glob", + "url": null, + "severity": "moderate", + "cwe": [ + "CWE-400" + ], + "cvss": { + "score": 0, + "vectorString": null + }, + "range": "*" + }, + "glob", + "glob" + ], + "effects": [ + "async-disk-cache", + "broccoli", + "broccoli-funnel", + "broccoli-persistent-filter", + "broccoli-plugin", + "ember-cli-babel", + "fs-updater", + "quick-temp", + "sync-disk-cache", + "testem" + ], + "range": "*", + "nodes": [ + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-funnel/node_modules/rimraf", + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter/node_modules/rimraf", + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-plugin/node_modules/rimraf", + "node_modules/@ember/legacy-built-in-components/node_modules/rimraf", + "node_modules/@ember/legacy-built-in-components/node_modules/sync-disk-cache/node_modules/rimraf", + "node_modules/@embroider/addon-shim/node_modules/rimraf", + "node_modules/async-disk-cache/node_modules/rimraf", + "node_modules/broccoli-babel-transpiler/node_modules/rimraf", + "node_modules/broccoli-caching-writer/node_modules/rimraf", + "node_modules/broccoli-concat/node_modules/rimraf", + "node_modules/broccoli-config-replace/node_modules/rimraf", + "node_modules/broccoli-debug/node_modules/rimraf", + "node_modules/broccoli-file-creator/node_modules/rimraf", + "node_modules/broccoli-filter/node_modules/rimraf", + "node_modules/broccoli-merge-trees/node_modules/rimraf", + "node_modules/broccoli-persistent-filter/node_modules/rimraf", + "node_modules/broccoli-stew/node_modules/rimraf", + "node_modules/broccoli-terser-sourcemap/node_modules/rimraf", + "node_modules/ember-api-store/node_modules/rimraf", + "node_modules/ember-auto-import/node_modules/rimraf", + "node_modules/ember-cli-babel/node_modules/rimraf", + "node_modules/ember-cli-htmlbars/node_modules/rimraf", + "node_modules/ember-cli-preprocess-registry/node_modules/rimraf", + "node_modules/ember-cli-sass/node_modules/rimraf", + "node_modules/ember-cli/node_modules/rimraf", + "node_modules/ember-fetch/node_modules/rimraf", + "node_modules/fs-updater/node_modules/rimraf", + "node_modules/quick-temp/node_modules/rimraf", + "node_modules/rimraf", + "node_modules/rimraf-real", + "node_modules/sync-disk-cache/node_modules/rimraf", + "vendor/ember-cli-pagination/node_modules/rimraf", + "vendor/ember-rl-dropdown/node_modules/rimraf", + "vendor/lacsso/node_modules/rimraf" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "sync-disk-cache": { + "name": "sync-disk-cache", + "severity": "moderate", + "isDirect": false, + "via": [ + "rimraf" + ], + "effects": [ + "broccoli-persistent-filter" + ], + "range": ">=2.0.0", + "nodes": [ + "node_modules/sync-disk-cache" + ], + "fixAvailable": { + "name": "ember-basic-dropdown", + "version": "8.0.4", + "isSemVerMajor": true + } + }, + "testem": { + "name": "testem", + "severity": "moderate", + "isDirect": false, + "via": [ + "consolidate", + "glob", + "minimatch", + "rimraf" + ], + "effects": [ + "ember-cli" + ], + "range": "3.19.0 - 3.21.5", + "nodes": [ + "node_modules/testem" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "tree-sync": { + "name": "tree-sync", + "severity": "moderate", + "isDirect": false, + "via": [ + "walk-sync" + ], + "effects": [ + "broccoli", + "broccoli-debug", + "ember-cli" + ], + "range": "*", + "nodes": [ + "node_modules/broccoli/node_modules/tree-sync", + "node_modules/ember-cli/node_modules/tree-sync", + "node_modules/tree-sync" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "walk-sync": { + "name": "walk-sync", + "severity": "moderate", + "isDirect": false, + "via": [ + "matcher-collection", + "minimatch" + ], + "effects": [ + "@ember-tooling/blueprint-model", + "@ember-tooling/classic-build-addon-blueprint", + "@ember/app-blueprint", + "broccoli-caching-writer", + "broccoli-filter", + "broccoli-funnel", + "broccoli-persistent-filter", + "broccoli-stew", + "broccoli-terser-sourcemap", + "ember-auto-import", + "ember-cli", + "ember-cli-htmlbars", + "ember-cli-typescript", + "fs-merger", + "tree-sync" + ], + "range": ">=0.2.0", + "nodes": [ + "node_modules/@ember-tooling/blueprint-model/node_modules/walk-sync", + "node_modules/@ember-tooling/classic-build-addon-blueprint/node_modules/walk-sync", + "node_modules/@ember/app-blueprint/node_modules/walk-sync", + "node_modules/@ember/legacy-built-in-components/node_modules/broccoli-persistent-filter/node_modules/walk-sync", + "node_modules/@embroider/addon-shim/node_modules/walk-sync", + "node_modules/broccoli-funnel/node_modules/walk-sync", + "node_modules/broccoli-stew/node_modules/broccoli-funnel/node_modules/walk-sync", + "node_modules/broccoli-stew/node_modules/walk-sync", + "node_modules/broccoli-terser-sourcemap/node_modules/walk-sync", + "node_modules/ember-api-store/node_modules/walk-sync", + "node_modules/ember-auto-import/node_modules/broccoli-funnel/node_modules/walk-sync", + "node_modules/ember-auto-import/node_modules/walk-sync", + "node_modules/ember-cli-babel/node_modules/walk-sync", + "node_modules/ember-cli-htmlbars/node_modules/walk-sync", + "node_modules/ember-cli-preprocess-registry/node_modules/walk-sync", + "node_modules/ember-cli-typescript/node_modules/walk-sync", + "node_modules/ember-cli/node_modules/broccoli-funnel/node_modules/walk-sync", + "node_modules/ember-cli/node_modules/tree-sync/node_modules/walk-sync", + "node_modules/ember-cli/node_modules/walk-sync", + "node_modules/ember-fetch/node_modules/walk-sync", + "node_modules/fs-merger/node_modules/walk-sync", + "node_modules/walk-sync", + "vendor/ember-cli-pagination/node_modules/walk-sync", + "vendor/ember-rl-dropdown/node_modules/walk-sync", + "vendor/lacsso/node_modules/walk-sync" + ], + "fixAvailable": { + "name": "ember-cli", + "version": "0.0.32", + "isSemVerMajor": true + } + }, + "yamljs": { + "name": "yamljs", + "severity": "moderate", + "isDirect": true, + "via": [ + "glob" + ], + "effects": [], + "range": ">=0.1.1", + "nodes": [ + "node_modules/yamljs" + ], + "fixAvailable": { + "name": "yamljs", + "version": "0.1.0", + "isSemVerMajor": true + } + } + }, + "metadata": { + "vulnerabilities": { + "info": 0, + "low": 0, + "moderate": 62, + "high": 1, + "critical": 0, + "total": 63 + }, + "dependencies": { + "prod": 8, + "dev": 1456, + "optional": 18, + "peer": 1, + "peerOptional": 0, + "total": 1479 + } + } +} diff --git a/scripts/test-ai-resource-confirm-errors.mjs b/scripts/test-ai-resource-confirm-errors.mjs new file mode 100644 index 0000000000..9eafa38bf4 --- /dev/null +++ b/scripts/test-ai-resource-confirm-errors.mjs @@ -0,0 +1,135 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import {readFileSync} from 'node:fs'; +import path from 'node:path'; +import {fileURLToPath} from 'node:url'; +import yaml from 'js-yaml'; +import YAML from 'yamljs'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const app = path.join(root, 'app'); +const urls = new Map(); +// The existing focused UI harness also loads real source with these Ember stubs. +function sourceUrl(filename) { + filename = path.resolve(filename); + if (urls.has(filename)) { return urls.get(filename); } + const source = readFileSync(filename, 'utf8') + .replace(/import \{ computed \} from '@ember\/object';/g, 'const computed = (...args) => args.at(-1);') + .replace(/import \{ observer \} from '@ember\/object';/g, 'const observer = (...args) => args.at(-1);') + .replace(/import \{ alias \} from '@ember\/object\/computed';/g, 'const alias = () => null;') + .replace(/import \{ service \} from '@ember\/service';/g, 'const service = () => null;') + .replace(/import ModalBase from 'lacsso\/components\/modal-base';/g, 'const ModalBase = {extend: value => value};') + .replace(/from '(ui\/[^']+|\.\.?\/[^']+)'/g, (_whole, specifier) => { + const resolved = specifier.startsWith('ui/') ? path.join(app, specifier.slice(3)) : path.resolve(path.dirname(filename), specifier); + return `from '${sourceUrl(resolved.endsWith('.js') ? resolved : resolved + '.js')}'`; + }); + const url = 'data:text/javascript;base64,' + Buffer.from(source).toString('base64'); + urls.set(filename, url); + return url; +} + +const labels = await import(sourceUrl(path.join(app, 'utils/ai-resource-review-labels.js'))); +const {publicError, CommandError} = await import(sourceUrl(path.join(app, 'utils/ai-command-contract.js'))); +const {default: definition} = await import(sourceUrl(path.join(app, 'components/modal-confirm-ai-upgrade/component.js'))); +const locales = ['de-de','en-us','fa-ir','fil-ph','fr-fr','hu-hu','ja-jp','ko-kr','pt-br','ru-ru','uk-ua','zh-hans','zh-tw']; +const privateText = 'PRIVATE_CANARY body.message detail JWT secret'; +function fixture(confirm) { + const writes = []; + const instance = { + saving: false, approved: false, errors: null, submitDisabled: false, + intl: {t: key => key}, commands: {confirmPendingPlan: confirm}, + get(key) { return key.split('.').reduce((row, part) => row && row[part], this); }, + set(key, value) { this[key] = value; writes.push([key, value]); }, + setProperties(values) { Object.assign(this, values); writes.push(values); }, + }; + return {instance, writes, confirm: () => definition.actions.confirm.call(instance)}; +} + +test('real 403 and 404 publicError confirmations show one safe permission explanation', async () => { + for (const status of [403, 404]) { + const result = publicError({status, body: {code: 'ApiKeyPolicyChanged', message: privateText, detail: privateText}}); + assert.equal(result.code, 'FORBIDDEN'); + const f = fixture(async () => result); const pending = f.confirm(); + assert.equal(f.instance.saving, true); + await pending; + assert.deepEqual(f.instance.errors, ['webmcp.forbidden']); + assert.equal(f.instance.approved, false); assert.equal(f.instance.saving, false); + assert.ok(!JSON.stringify(f.instance.errors).includes(privateText)); + } +}); + +test('conflict session and stale public codes ask for a fresh preview', async () => { + const results = [publicError({status: 409, body: {code: 'ResourceChangePlanStale', message: privateText}}), + publicError({status: 401, body: {message: privateText}}), + publicError(new CommandError('STALE_REFERENCE')), publicError(new CommandError('CONTEXT_CHANGED'))]; + for (const result of results) { + const f = fixture(async () => result); await f.confirm(); + assert.deepEqual(f.instance.errors, ['webmcp.stale']); assert.equal(f.instance.saving, false); + } + for (const code of ['CONFLICT', 'SESSION_REQUIRED', 'STALE_REFERENCE', 'STALE_REF', 'CONTEXT_CHANGED']) { + assert.equal(labels.resourceConfirmationErrorKey(code), 'webmcp.stale'); + } +}); + +test('the pure mapping accepts only a public code and never raw errors or server text', async () => { + assert.equal(labels.resourceConfirmationErrorKey('FORBIDDEN'), 'webmcp.forbidden'); + for (const value of [undefined, null, '', 'ApiKeyPolicyChanged', privateText, {code: 'FORBIDDEN', message: privateText}, + {get body() { throw new Error('Raw error body must not be read'); }}]) { + assert.equal(labels.resourceConfirmationErrorKey(value), 'webmcp.failed'); + } + for (const result of [publicError({status: 500, body: {code: privateText, message: privateText, detail: privateText}}), + {status: 'unknown', code: 'UNKNOWN_RESULT', message: privateText, detail: privateText}]) { + const f = fixture(async () => result); await f.confirm(); + assert.deepEqual(f.instance.errors, ['webmcp.failed']); assert.equal(f.instance.saving, false); + assert.ok(!JSON.stringify(f.instance.errors).includes(privateText)); + } +}); + +test('success rejection and saving finally retain the existing confirmation lifecycle', async () => { + const success = fixture(async () => ({status: 'succeeded', confirmationState: 'approved'})); + await success.confirm(); assert.equal(success.instance.approved, true); assert.equal(success.instance.errors, null); + assert.equal(success.instance.saving, false); + const rejected = fixture(async () => { throw new Error(privateText); }); + await rejected.confirm(); assert.deepEqual(rejected.instance.errors, ['webmcp.failed']); assert.equal(rejected.instance.saving, false); + let calls = 0; const disabled = fixture(async () => { calls++; }); disabled.instance.submitDisabled = true; + assert.equal(disabled.confirm(), undefined); assert.equal(calls, 0); assert.equal(disabled.writes.length, 0); + for (const field of ['isDestroyed', 'isDestroying']) { + let resolve; const f = fixture(() => new Promise(done => { resolve = done; })); const pending = f.confirm(); + const before = f.writes.length; f.instance[field] = true; resolve({status: 'forbidden', code: 'FORBIDDEN'}); + await pending; assert.equal(f.writes.length, before); + } +}); + +test('forbidden guidance is translated in all thirteen actual locale files with fixed safe keys', () => { + // Match the actual translation-json-tree/environment parser for complete files. + // Also parse each new entry strictly without rewriting unrelated legacy YAML. + const english = YAML.parse(readFileSync(path.join(root, 'translations/en-us.yaml'), 'utf8')).webmcp.forbidden; + const texts = []; + for (const locale of locales) { + const source = readFileSync(path.join(root, 'translations', locale + '.yaml'), 'utf8'); + const document = YAML.parse(source); + const lines = source.split(/\r?\n/), start = lines.indexOf('webmcp:'); + const next = lines.findIndex((line, index) => index > start && line.length > 0 && !line.startsWith(' ') && !line.startsWith('#')); + const entries = lines.slice(start + 1, next === -1 ? undefined : next).filter(line => line.startsWith(' forbidden:')); + assert.equal(entries.length, 1, locale + ': one exact new key'); + assert.equal(yaml.load('webmcp:\n' + entries[0] + '\n').webmcp.forbidden, document.webmcp.forbidden, locale); + for (const key of ['forbidden', 'stale', 'failed']) { + assert.equal(typeof document.webmcp[key], 'string', locale + ': webmcp.' + key); + assert.ok(document.webmcp[key].length > 10, locale + ': webmcp.' + key); + } + const text = document.webmcp.forbidden; texts.push(text); + if (locale !== 'en-us') { assert.notEqual(text, english, locale); } + assert.doesNotMatch(text, /<[^>]+>|JWT|secret|detail|message|\{\{|404|FORBIDDEN|ApiKeyPolicyChanged/i, locale); + } + assert.equal(new Set(texts).size, 13); + const traditional = YAML.parse(readFileSync(path.join(root, 'translations/zh-tw.yaml'), 'utf8')).webmcp.forbidden; + assert.match(traditional, /帳號或 API Key/); assert.match(traditional, /重新查詢/); assert.match(traditional, /預覽/); assert.match(traditional, /管理員/); +}); + +test('the original escaped alert renderer and other Catalog error paths stay unchanged', () => { + const template = readFileSync(path.join(app, 'components/modal-confirm-ai-upgrade/template.hbs'), 'utf8'); + assert.match(template, /\{\{top-errors errors=this.errors\}\}/); assert.doesNotMatch(template, /\{\{\{|htmlSafe/); + const source = readFileSync(path.join(app, 'components/modal-confirm-ai-upgrade/component.js'), 'utf8'); + assert.match(source, /resourceConfirmationErrorKey\(result.code\)/); + assert.doesNotMatch(source, /result\.(?:body|detail|message)|error\.(?:body|detail|message)/); +}); diff --git a/scripts/test-ui-npm-audit.js b/scripts/test-ui-npm-audit.js index 7d5ab4a65a..9286e0efc5 100644 --- a/scripts/test-ui-npm-audit.js +++ b/scripts/test-ui-npm-audit.js @@ -376,3 +376,111 @@ test('cold-installed addon node_modules are audited packages, while owned source tree['vendor/lacsso'][1] = entry('node_modules', 'link'); assert.throws(() => readReviewedSources(root, io), { message: 'BROWSER_SOURCE_SYMLINK_UNREVIEWED' }); }); + + +// Public npm12 primary report fixtures, not the failed CI run bytes. Complete +// original-parser RED evidence stays with the capture receipts; these portable +// cases exercise the current policy with the exact raw report structures. +{ +const { createHash } = require('node:crypto'); +const candidate = require('./check-ui-npm-audit'); +const fixtureRoot = path.join(__dirname, 'fixtures/npm-audit'); +const captured = JSON.parse(fs.readFileSync(path.join(fixtureRoot, 'captures-and-lock-projection.json'), 'utf8')); +function input(patched = true) { + const selected = captured.captures[patched ? 'after' : 'before']; + const bytes = fs.readFileSync(path.join(fixtureRoot, selected.rawFile)); + assert.equal(createHash('sha256').update(bytes).digest('hex'), selected.rawSha256); + const lock = clone(captured.lock); + if (patched) Object.assign(lock.packages['node_modules/follow-redirects'], captured.patchedFollowRedirectsNode); + return {audit: JSON.parse(bytes), lock, pending: clone(captured.pending), + now: new Date(selected.capturedUtc), npmExitCode: selected.npmExitCode}; +} +const rejected = (value, code) => { + const result = candidate.evaluateAudit(value); + assert.equal(result.ok, false); assert.equal(result.outcome, 'FAIL_CLOSED'); assert.equal(result.failureCode, code); +}; + +test('captured primary raw still blocks the fixable unregistered High after normalization', () => { + const value = input(false); + assert.equal(value.audit.vulnerabilities['follow-redirects'].fixAvailable, true); + rejected(value, 'UNREVIEWED_HIGH_NODE'); +}); + +test('official patched-lock raw passes clean High/Critical without mutating raw Moderate or claiming runtime unaffected', () => { + const value = input(), before = JSON.stringify(value.audit); + const result = candidate.evaluateAudit(value); + assert.equal(result.ok, true); assert.equal(result.outcome, 'PASS_HIGH_CRITICAL_CLEAN'); + assert.deepEqual(result.totals, value.audit.metadata.vulnerabilities); + assert.equal(result.totals.high, 0); assert.equal(result.totals.critical, 0); assert.equal(result.totals.moderate, 63); + assert.equal(result.knownPending, null); assert.equal(result.runtimeNotAffectedClaim, false); + assert.equal(JSON.stringify(value.audit), before); +}); + +test('stable exact normalization removes repeated meta and identical objects while retaining different source and range', () => { + const value = input(), via = value.audit.vulnerabilities.glob.via; + const objects = via.filter(item => typeof item === 'object'); + assert.equal(objects.length, 2); assert.equal(objects[0].url, objects[1].url); + assert.notEqual(objects[0].source, objects[1].source); assert.notEqual(objects[0].range, objects[1].range); + assert.equal(candidate.exactVia(via).filter(item => typeof item === 'object').length, 2); + const reordered = Object.fromEntries(Object.entries(objects[0]).reverse()); + assert.deepEqual(candidate.exactVia(['glob', 'glob', objects[0], reordered, objects[1]]), ['glob', objects[0], objects[1]]); +}); + +test('alias identity requires actual lock package name plus the exact declared npm alias edge', () => { + for (const alter of [ + value => { value.lock.packages['node_modules/glob-real'].name = 'different-package'; }, + value => { value.lock.packages['node_modules/glob'].dependencies['glob-real'] = 'npm:different-package@13.0.6'; }, + value => { delete value.lock.packages['node_modules/glob'].dependencies['glob-real']; }, + ]) { + const value = input(); alter(value); rejected(value, 'AUDIT_NODE_LOCK_MISMATCH'); + } +}); + +test('calculated advisory digest and range must match the real npm12 alias derivation', () => { + for (const alter of [ + via => { via.source = 'A'.repeat(86) + '=='; }, + via => { via.range = '>=9'; }, + via => { via.title += ' changed'; }, + ]) { + const value = input(), via = value.audit.vulnerabilities.glob.via.find(item => typeof item.source === 'string'); + alter(via); rejected(value, 'AUDIT_ADVISORY_SHAPE_INVALID'); + } +}); + +test('null-url calculated meta requires its real alias implementation-to-child lock edge', () => { + const value = input(); delete value.lock.packages['node_modules/rimraf-real'].dependencies.glob; + rejected(value, 'AUDIT_ADVISORY_SHAPE_INVALID'); + const unknown = input(); unknown.audit.vulnerabilities.rimraf.via[0].title = 'Unknown metadata'; + rejected(unknown, 'AUDIT_ADVISORY_SHAPE_INVALID'); +}); + +test('unknown advisory keys and arbitrary null source entries remain fail closed', () => { + const value = input(); value.audit.vulnerabilities.glob.via[0].unexpected = true; + rejected(value, 'AUDIT_ADVISORY_SHAPE_INVALID'); + const malformed = input(); malformed.audit.vulnerabilities.glob.via.push(null); + rejected(malformed, 'AUDIT_ADVISORY_SHAPE_INVALID'); +}); + +test('Critical still blocks first and a newly promoted unregistered High cannot borrow alias normalization', () => { + const critical = input(); critical.audit.vulnerabilities.glob.severity = 'critical'; + critical.audit.metadata.vulnerabilities.moderate--; critical.audit.metadata.vulnerabilities.critical++; + rejected(critical, 'CRITICAL_VULNERABILITY'); + const high = input(); high.audit.vulnerabilities['follow-redirects'] = input(false).audit.vulnerabilities['follow-redirects']; + high.audit.metadata.vulnerabilities.high++; high.audit.metadata.vulnerabilities.total++; high.npmExitCode = 1; + rejected(high, 'UNREVIEWED_HIGH_NODE'); +}); + +test('a Moderate wrapper still cannot hide a higher severity direct advisory', () => { + const value = input(); value.audit.vulnerabilities.glob.via[0].severity = 'high'; + rejected(value, 'AUDIT_SEVERITY_INCONSISTENT'); +}); + +test('review expiry, patched-version policy mutation and npm exit consistency keep their original gates', () => { + const expired = input(); expired.now = new Date('2026-11-05T00:00:00Z'); + rejected(expired, 'PENDING_REVIEW_EXPIRED_OR_INVALID'); + const policy = input(); policy.pending.upstreamPatchedVersion = '1.16.2'; + rejected(policy, 'PENDING_POLICY_INVALID'); + const status = input(); status.npmExitCode = 1; + rejected(status, 'NPM_EXIT_OR_NETWORK_ERROR'); +}); +} diff --git a/scripts/test-ui-release-dependency-patches.js b/scripts/test-ui-release-dependency-patches.js index fe018a7339..a6809d7bde 100644 --- a/scripts/test-ui-release-dependency-patches.js +++ b/scripts/test-ui-release-dependency-patches.js @@ -4,6 +4,7 @@ const assert = require('node:assert/strict'); const http = require('node:http'); const { spawnSync } = require('node:child_process'); const { test } = require('node:test'); +const vm = require('node:vm'); const redirects = require('follow-redirects'); const MarkdownIt = require('markdown-it'); @@ -34,7 +35,7 @@ function get(url, options) { test('official dependency patches are installed at every locked occurrence', () => { const lock = require('../package-lock.json'); - for (const [name, version] of Object.entries({'follow-redirects': '1.16.1', 'markdown-it': '14.3.3'})) { + for (const [name, version] of Object.entries({'follow-redirects': '1.16.2', 'markdown-it': '14.3.3'})) { const occurrences = Object.entries(lock.packages).filter(([namePath]) => namePath.endsWith(`node_modules/${name}`)); assert.ok(occurrences.length > 0); for (const [namePath, entry] of occurrences) { @@ -75,6 +76,33 @@ test('cross-origin redirects strip array credentials and regex-significant custo } }); +test('cross-realm sensitiveHeaders arrays strip custom credentials across origins', async () => { + const target = await listen((request, response) => response.end(JSON.stringify(request.headers))); + const origin = await listen((request, response) => { + response.writeHead(302, {Location: `http://127.0.0.1:${target.address().port}/target`}); + response.end(); + }); + try { + const sensitiveHeaders = vm.runInNewContext('["X-Token^Key", "X-Token|Key"]'); + assert.equal(Array.isArray(sensitiveHeaders), true); + assert.equal(sensitiveHeaders instanceof Array, false, 'exercise the foreign-realm array boundary'); + for (const headers of [ + {'Authorization': 'test-auth', 'Cookie': 'test-cookie', 'X-Token^Key': 'test-one', 'X-Token|Key': 'test-two', 'X-Control': 'keep'}, + vm.runInNewContext('["Authorization", "test-auth", "Cookie", "test-cookie", "X-Token^Key", "test-one", "X-Token|Key", "test-two", "X-Control", "keep"]'), + ]) { + const received = await get(`http://127.0.0.1:${origin.address().port}/redirect`, {headers, sensitiveHeaders}); + assert.equal(received.authorization, undefined); + assert.equal(received.cookie, undefined); + assert.equal(received['x-token^key'], undefined); + assert.equal(received['x-token|key'], undefined); + assert.equal(received['x-control'], 'keep'); + } + } finally { + await close(origin); + await close(target); + } +}); + test('same-origin redirects retain legitimate authentication headers', async () => { const server = await listen((request, response) => { if (request.url === '/redirect') { @@ -86,10 +114,13 @@ test('same-origin redirects retain legitimate authentication headers', async () }); try { const received = await get(`http://127.0.0.1:${server.address().port}/redirect`, { - headers: {Authorization: 'test-auth', Cookie: 'test-cookie'}, + headers: {Authorization: 'test-auth', Cookie: 'test-cookie', 'X-Token^Key': 'test-custom', 'X-Control': 'keep'}, + sensitiveHeaders: vm.runInNewContext('["X-Token^Key"]'), }); assert.equal(received.authorization, 'test-auth'); assert.equal(received.cookie, 'test-cookie'); + assert.equal(received['x-token^key'], 'test-custom'); + assert.equal(received['x-control'], 'keep'); } finally { await close(server); } diff --git a/translations/de-de.yaml b/translations/de-de.yaml index 29bce82d97..bea1c9185e 100644 --- a/translations/de-de.yaml +++ b/translations/de-de.yaml @@ -4490,6 +4490,7 @@ webmcp: approved: "Plan genehmigt. Die KI kann ihn jetzt ausführen." review: "Ausstehendes Upgrade prüfen" stale: "Die Sitzung, die Umgebung oder der Plan wurde geändert. Bitten Sie die KI, erneut eine Vorschau zu erstellen." + forbidden: "Das aktuelle Konto oder der API-Schlüssel darf diese Aktion für dieses Ziel nicht ausführen. Suchen Sie das Ziel erneut und erstellen Sie eine neue Vorschau, oder wenden Sie sich an einen Administrator, um die Berechtigungen zu prüfen." failed: "Der Plan konnte nicht genehmigt werden. Prüfen Sie den Fehler und versuchen Sie es erneut." expires: "Gültig bis" dismiss: "Vorschau schließen" diff --git a/translations/en-us.yaml b/translations/en-us.yaml index 75e6f2fdda..620294c363 100644 --- a/translations/en-us.yaml +++ b/translations/en-us.yaml @@ -4887,6 +4887,7 @@ webmcp: approved: "Plan approved. The AI can now execute it." review: "Review pending upgrade" stale: "The session, environment, or plan changed. Ask the AI to preview again." + forbidden: "The current account or API Key is not allowed to perform this operation on this target. Find the target again and generate a new preview, or contact an administrator to check permissions." failed: "The plan could not be approved. Review the error and try again." expires: "Expires" dismiss: "Dismiss preview" diff --git a/translations/fa-ir.yaml b/translations/fa-ir.yaml index d0ac9fb7c6..f612377492 100644 --- a/translations/fa-ir.yaml +++ b/translations/fa-ir.yaml @@ -4380,6 +4380,7 @@ webmcp: approved: "برنامه تأیید شد. هوش مصنوعی اکنون می‌تواند آن را اجرا کند." review: "بررسی ارتقای در انتظار" stale: "نشست، محیط یا برنامه تغییر کرده است. از هوش مصنوعی بخواهید دوباره پیش‌نمایش را ایجاد کند." + forbidden: "حساب فعلی یا کلید API مجاز به انجام این عملیات روی این هدف نیست. هدف را دوباره جستجو و یک پیش‌نمایش تازه ایجاد کنید، یا برای بررسی مجوزها با مدیر سیستم تماس بگیرید." failed: "برنامه تأیید نشد. خطا را بررسی کنید و دوباره تلاش کنید." expires: "زمان انقضا" dismiss: "بستن پیش‌نمایش" diff --git a/translations/fil-ph.yaml b/translations/fil-ph.yaml index ad33baa42a..3186eb06ca 100644 --- a/translations/fil-ph.yaml +++ b/translations/fil-ph.yaml @@ -4437,6 +4437,7 @@ webmcp: approved: "Naaprubahan ang plano. Maaari na itong isagawa ng AI." review: "Suriin ang nakabinbing pag-upgrade" stale: "Nagbago ang session, kapaligiran, o plano. Hilingin sa AI na gumawa muli ng paunang tingin." + forbidden: "Hindi pinapayagan ang kasalukuyang account o API Key na gawin ang operasyong ito sa target na ito. Hanapin muli ang target at gumawa ng bagong preview, o makipag-ugnayan sa administrator upang suriin ang mga pahintulot." failed: "Hindi maaprubahan ang plano. Suriin ang error at subukang muli." expires: "Mag-e-expire" dismiss: "Isara ang paunang tingin" diff --git a/translations/fr-fr.yaml b/translations/fr-fr.yaml index 402dd4dc2c..27d61a731d 100644 --- a/translations/fr-fr.yaml +++ b/translations/fr-fr.yaml @@ -4435,6 +4435,7 @@ webmcp: approved: "Plan approuvé. L’IA peut maintenant l’exécuter." review: "Vérifier la mise à niveau en attente" stale: "La session, l’environnement ou le plan a changé. Demandez à l’IA de générer un nouvel aperçu." + forbidden: "Le compte actuel ou la clé API ne permet pas d’effectuer cette opération sur cette cible. Recherchez à nouveau la cible et générez un nouvel aperçu, ou contactez un administrateur pour vérifier les autorisations." failed: "Le plan n’a pas pu être approuvé. Examinez l’erreur et réessayez." expires: "Expire le" dismiss: "Fermer l’aperçu" diff --git a/translations/hu-hu.yaml b/translations/hu-hu.yaml index 322d13f7d1..db4d9e1183 100644 --- a/translations/hu-hu.yaml +++ b/translations/hu-hu.yaml @@ -4453,6 +4453,7 @@ webmcp: approved: "A terv jóváhagyva. Az MI most már végrehajthatja." review: "A függőben lévő frissítés áttekintése" stale: "A munkamenet, a környezet vagy a terv megváltozott. Kérje meg az MI-t, hogy készítsen új előnézetet." + forbidden: "A jelenlegi fiók vagy API-kulcs nem jogosult a művelet végrehajtására ennél a célnál. Keresse meg újra a célt, és készítsen új előnézetet, vagy kérje a rendszergazdától a jogosultságok ellenőrzését." failed: "A tervet nem sikerült jóváhagyni. Ellenőrizze a hibát, és próbálja újra." expires: "Lejárat" dismiss: "Előnézet bezárása" diff --git a/translations/ja-jp.yaml b/translations/ja-jp.yaml index e6caba003a..3650a010c3 100644 --- a/translations/ja-jp.yaml +++ b/translations/ja-jp.yaml @@ -4635,6 +4635,7 @@ webmcp: approved: "プランが承認されました。AIは実行できるようになりました。" review: "保留中のアップグレードを確認" stale: "セッション、環境、またはプランが変更されました。AIにもう一度プレビューを作成するよう依頼してください。" + forbidden: "現在のアカウントまたは API キーでは、この対象に対する操作は許可されていません。対象を再検索して新しいプレビューを作成するか、管理者に権限を確認してください。" failed: "プランを承認できませんでした。エラーを確認して、もう一度お試しください。" expires: "有効期限" dismiss: "プレビューを閉じる" diff --git a/translations/ko-kr.yaml b/translations/ko-kr.yaml index 00e09a0319..ab26d4bf28 100644 --- a/translations/ko-kr.yaml +++ b/translations/ko-kr.yaml @@ -4287,6 +4287,7 @@ webmcp: approved: "계획이 승인되었습니다. 이제 AI가 실행할 수 있습니다." review: "대기 중인 업그레이드 검토" stale: "세션, 환경 또는 계획이 변경되었습니다. AI에게 미리 보기를 다시 생성하도록 요청하세요." + forbidden: "현재 계정 또는 API 키로는 이 대상에 대한 작업을 수행할 수 없습니다. 대상을 다시 조회하고 새 미리 보기를 만들거나 관리자에게 권한을 문의하세요." failed: "계획을 승인할 수 없습니다. 오류를 확인한 후 다시 시도하세요." expires: "만료" dismiss: "미리 보기 닫기" diff --git a/translations/pt-br.yaml b/translations/pt-br.yaml index 9d75169521..a2ef7eee19 100644 --- a/translations/pt-br.yaml +++ b/translations/pt-br.yaml @@ -4441,6 +4441,7 @@ webmcp: approved: "Plano aprovado. A IA já pode executá-lo." review: "Revisar a atualização pendente" stale: "A sessão, o ambiente ou o plano mudou. Peça à IA para gerar uma nova prévia." + forbidden: "A conta ou a chave de API atual não tem permissão para executar esta operação neste destino. Pesquise o destino novamente e gere uma nova prévia, ou entre em contato com um administrador para verificar as permissões." failed: "Não foi possível aprovar o plano. Revise o erro e tente novamente." expires: "Expira em" dismiss: "Fechar prévia" diff --git a/translations/ru-ru.yaml b/translations/ru-ru.yaml index 530fc8c850..aff3822957 100644 --- a/translations/ru-ru.yaml +++ b/translations/ru-ru.yaml @@ -4461,6 +4461,7 @@ webmcp: approved: "План одобрен. Теперь ИИ может его выполнить." review: "Проверить ожидающее обновление" stale: "Сеанс, окружение или план изменились. Попросите ИИ снова подготовить предварительный просмотр." + forbidden: "Текущей учётной записи или ключу API не разрешено выполнять эту операцию с этим объектом. Найдите объект заново и создайте новый предварительный просмотр либо обратитесь к администратору для проверки прав доступа." failed: "Не удалось одобрить план. Проверьте ошибку и повторите попытку." expires: "Срок действия" dismiss: "Закрыть предварительный просмотр" diff --git a/translations/uk-ua.yaml b/translations/uk-ua.yaml index 94d5619086..2cf5d88500 100644 --- a/translations/uk-ua.yaml +++ b/translations/uk-ua.yaml @@ -4500,6 +4500,7 @@ webmcp: approved: "План схвалено. Тепер ШІ може його виконати." review: "Перевірити оновлення, що очікує" stale: "Сеанс, середовище або план змінилися. Попросіть ШІ знову підготувати попередній перегляд." + forbidden: "Поточний обліковий запис або ключ API не має дозволу виконувати цю операцію для цього об’єкта. Знову знайдіть цільовий об’єкт і створіть новий попередній перегляд або зверніться до адміністратора для перевірки дозволів." failed: "Не вдалося схвалити план. Перевірте помилку та повторіть спробу." expires: "Термін дії" dismiss: "Закрити попередній перегляд" diff --git a/translations/zh-hans.yaml b/translations/zh-hans.yaml index 6eba4eb31c..6139a1a3ae 100644 --- a/translations/zh-hans.yaml +++ b/translations/zh-hans.yaml @@ -4330,6 +4330,7 @@ webmcp: approved: "计划已批准。AI 现在可以执行此计划。" review: "审核待执行的升级" stale: "会话、环境或计划已更改。请让 AI 重新生成预览。" + forbidden: "当前账号或 API Key 无法对此目标执行操作。请重新查询目标并生成预览,或联系管理员确认权限。" failed: "无法批准此计划。请检查错误后重试。" expires: "到期时间" dismiss: "关闭预览" diff --git a/translations/zh-tw.yaml b/translations/zh-tw.yaml index 89086ba65a..3fa907a572 100644 --- a/translations/zh-tw.yaml +++ b/translations/zh-tw.yaml @@ -4663,6 +4663,7 @@ webmcp: approved: "計畫已核准。AI 現在可以執行此計畫。" review: "檢視待執行的升級" stale: "工作階段、環境或計畫已變更。請讓 AI 重新產生預覽。" + forbidden: "目前的帳號或 API Key 無法對此目標執行操作。請重新查詢目標並產生預覽,或聯絡管理員確認權限。" failed: "無法核准此計畫。請檢查錯誤後再試一次。" expires: "到期時間" dismiss: "關閉預覽"