Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SALTO-6517: fix static file path collision #6518

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/adapter-utils/src/nacl_case_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const allCapsCamelCaseRegex = /[A-Z]([A-Z][a-z])/g
export const pathNaclCase = (name?: string): string =>
(name ? name.split(NACL_ESCAPING_SUFFIX_SEPARATOR)[0] : '').slice(0, MAX_PATH_LENGTH)

// Converts a nacl case to a file system safe name. Use it (instead of pathNaclCase) if the file name must be unique
export const fileNameNaclCase = (name: string): string => name.replace('@', '.')

Comment on lines +28 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added it in this PR #6625
As suggested by @shir-reifenberg

// Trim part of a file name to comply with filesystem restrictions
// This assumes the filesystem does not allow path parts to be over
// MAX_PATH_LENGTH long in byte length
Expand Down
21 changes: 20 additions & 1 deletion packages/adapter-utils/test/nacl_case_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
* CERTAIN THIRD PARTY SOFTWARE MAY BE CONTAINED IN PORTIONS OF THE SOFTWARE. See NOTICE FILE AT https://github.com/salto-io/salto/blob/main/NOTICES
*/
import _ from 'lodash'
import { invertNaclCase, naclCase, normalizeFilePathPart, pathNaclCase, prettifyName } from '../src/nacl_case_utils'
import {
invertNaclCase,
naclCase,
fileNameNaclCase,
normalizeFilePathPart,
pathNaclCase,
prettifyName,
} from '../src/nacl_case_utils'

describe('naclCase utils', () => {
const generateRandomChar = (): string => String.fromCharCode(Math.random() * 65535)
Expand Down Expand Up @@ -137,6 +144,18 @@ describe('naclCase utils', () => {
})
})

describe('fileNameNaclCase func', () => {
it('should return empty string for empty input', () => {
expect(fileNameNaclCase('')).toEqual('')
})
it('should replace @ with . at the end of the input', () => {
expect(fileNameNaclCase('name@')).toEqual('name.')
})
it('should replace @ with . in the middle of the input', () => {
expect(fileNameNaclCase('name@name')).toEqual('name.name')
})
})

describe('normalizeStaticResourcePath func', () => {
describe('With a short path', () => {
const shortPaths = ['lalala.txt', 'aבגדe.טקסט', 'noExtension']
Expand Down
4 changes: 2 additions & 2 deletions packages/jira-adapter/src/filters/icon_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import _ from 'lodash'
import { client as clientUtils } from '@salto-io/adapter-components'
import Joi from 'joi'
import { createSchemeGuard, naclCase, pathNaclCase } from '@salto-io/adapter-utils'
import { createSchemeGuard, fileNameNaclCase } from '@salto-io/adapter-utils'
import { JIRA } from '../constants'
import JiraClient from '../client/client'

Expand Down Expand Up @@ -75,7 +75,7 @@ export const setIconContent = async ({
}): Promise<void> => {
const iconContent = await getIconContent(link, client)
instance.value[fieldName] = new StaticFile({
filepath: `${JIRA}/${instance.elemID.typeName}/${pathNaclCase(naclCase(instance.value.name))}.png`,
filepath: `${JIRA}/${instance.elemID.typeName}/${fileNameNaclCase(instance.elemID.name)}.png`,
content: iconContent,
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { filterUtils, client as clientUtils } from '@salto-io/adapter-components'
import { InstanceElement, Element, StaticFile, Values } from '@salto-io/adapter-api'
import _ from 'lodash'
import { naclCase } from '@salto-io/adapter-utils'
import { createEmptyType, getFilterParams, mockClient } from '../../utils'
import JiraClient from '../../../src/client/client'
import objectTypeIconFilter from '../../../src/filters/assets/object_type_icon'
Expand Down Expand Up @@ -43,7 +44,7 @@ describe('object type icon filter', () => {
})
describe('on fetch', () => {
beforeEach(async () => {
objectTypeIconInstance = new InstanceElement('objectType1', objectTypeIconType, {
objectTypeIconInstance = new InstanceElement(naclCase('object_type:1'), objectTypeIconType, {
name: 'objectTypeIconName',
id: 12,
})
Expand Down Expand Up @@ -78,7 +79,7 @@ describe('object type icon filter', () => {
name: 'objectTypeIconName',
id: 12,
icon: new StaticFile({
filepath: 'jira/ObjectTypeIcon/objectTypeIconName.png',
filepath: 'jira/ObjectTypeIcon/object_type_1.uf.png',
encoding: 'binary',
content,
}),
Expand Down
14 changes: 9 additions & 5 deletions packages/jira-adapter/test/filters/issue_type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
import { filterUtils, client as clientUtils } from '@salto-io/adapter-components'
import { BuiltinTypes, ElemID, InstanceElement, ObjectType, StaticFile, toChange } from '@salto-io/adapter-api'
import { naclCase } from '@salto-io/adapter-utils'
import { ISSUE_TYPE_NAME, JIRA } from '../../src/constants'
import { getFilterParams, mockClient } from '../utils'
import issueTypeFilter from '../../src/filters/issue_type'
Expand Down Expand Up @@ -105,8 +106,11 @@ describe('issueTypeFilter', () => {
mockGet.mockClear()
})
it('should set icon content', async () => {
const anotherInstance = instance.clone()
anotherInstance.value.name = 'anotherInstance'
const anotherInstance = new InstanceElement(naclCase('another instance'), issueType, {
name: 'anotherInstance',
description: 'anotherInstanceDescription',
avatarId: 1,
})
mockGet.mockImplementation(params => {
if (params.url === '/rest/api/3/universal_avatar/view/type/issuetype/avatar/1') {
return {
Expand All @@ -120,15 +124,15 @@ describe('issueTypeFilter', () => {
expect(instance.value.avatar).toBeDefined()
expect(instance.value.avatar).toEqual(
new StaticFile({
filepath: 'jira/IssueType/instanceName.png',
filepath: 'jira/IssueType/instance.png',
encoding: 'binary',
content,
}),
)
expect(anotherInstance.value.avatar).toBeDefined()
expect(anotherInstance.value.avatar).toEqual(
new StaticFile({
filepath: 'jira/IssueType/anotherInstance.png',
filepath: 'jira/IssueType/another_instance.s.png',
encoding: 'binary',
content,
}),
Expand All @@ -149,7 +153,7 @@ describe('issueTypeFilter', () => {
expect(instance.value.avatar).toBeDefined()
expect(instance.value.avatar).toEqual(
new StaticFile({
filepath: 'jira/IssueType/instanceName.png',
filepath: 'jira/IssueType/instance.png',
encoding: 'binary',
content: Buffer.from('a string, not a buffer.'),
}),
Expand Down
4 changes: 2 additions & 2 deletions packages/okta-adapter/src/logo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from '@salto-io/adapter-api'
import FormData from 'form-data'
import { elements as elementsUtils } from '@salto-io/adapter-components'
import { getParent, getParents, normalizeFilePathPart, pathNaclCase } from '@salto-io/adapter-utils'
import { getParent, getParents, fileNameNaclCase, normalizeFilePathPart, pathNaclCase } from '@salto-io/adapter-utils'
import OktaClient from './client/client'
import { getOktaError } from './deprecated_deployment'
import { APP_LOGO_TYPE_NAME, BRAND_LOGO_TYPE_NAME, FAV_ICON_TYPE_NAME, OKTA } from './constants'
Expand Down Expand Up @@ -159,7 +159,7 @@ export const getLogo = async ({
}
// Use the full NaCL name (including suffix) to avoid naming collisions, but replace '@' with '.' to ensure file
// names are valid across all operating systems.
const resourcePathName = `${normalizeFilePathPart(logoName.replace('@', '.'))}.${contentType}`
const resourcePathName = `${normalizeFilePathPart(fileNameNaclCase(logoName))}.${contentType}`
const logoId = extractIdFromUrl(link)
const refParents = parents.map(parent => new ReferenceExpression(parent.elemID, parent))
const logo = new InstanceElement(
Expand Down