Skip to content

Commit

Permalink
Merge pull request #169 from snyk/fix/org-name-header-fix
Browse files Browse the repository at this point in the history
fix: fixed http library to properly set API header with organization …
  • Loading branch information
Arvi3d committed Feb 21, 2023
2 parents 7c6d401 + e0fba01 commit bf87e11
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 56 deletions.
1 change: 0 additions & 1 deletion src/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ export async function analyzeFolders(options: FileAnalysisOptions): Promise<File
...options.connection,
...options.fileOptions,
languages: options.languages,
...(options.analysisContext ? { analysisContext: options.analysisContext } : {}),
});
if (fileBundle === null) return null;

Expand Down
3 changes: 1 addition & 2 deletions src/bundles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,9 @@ export async function createBundleFromFolders(options: CreateBundleFromFoldersOp
}

const bundleOptions = {
...pick(options, ['baseURL', 'sessionToken', 'source', 'requestId']),
...pick(options, ['baseURL', 'sessionToken', 'source', 'requestId', 'org']),
baseDir,
files: bundleFiles,
...(options.analysisContext?.org?.name ? { org: options.analysisContext.org.name } : {}),
};

// Create remote bundle
Expand Down
45 changes: 16 additions & 29 deletions src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,14 @@ export async function getFilters(
return generateError<GenericErrorTypes>(res.errorCode, GENERIC_ERROR_MESSAGES, apiName);
}

function prepareTokenHeaders(sessionToken: string) {
function commonHttpHeaders(options: ConnectionOptions) {
return {
'Session-Token': sessionToken,
'Session-Token': options.sessionToken,
// We need to be able to test code-client without deepcode locally
Authorization: `Bearer ${sessionToken}`,
Authorization: `Bearer ${options.sessionToken}`,
source: options.source,
...(options.requestId && { 'snyk-request-id': options.requestId }),
...(options.org && { 'snyk-org-name': options.org }),
};
}

Expand Down Expand Up @@ -221,11 +224,9 @@ export async function createBundle(
const payloadBody = await compressAndEncode(options.files);
const payload: Payload = {
headers: {
...prepareTokenHeaders(options.sessionToken),
source: options.source,
...(options.requestId && { 'snyk-request-id': options.requestId }),
...{ 'content-type': 'application/octet-stream', 'content-encoding': 'gzip' },
...(options.org && { 'snyk-org-name': options.org }),
'content-type': 'application/octet-stream',
'content-encoding': 'gzip',
...commonHttpHeaders(options),
},
url: `${options.baseURL}/bundle`,
method: 'post',
Expand Down Expand Up @@ -260,10 +261,7 @@ interface CheckBundleOptions extends ConnectionOptions {
export async function checkBundle(options: CheckBundleOptions): Promise<Result<RemoteBundle, CheckBundleErrorCodes>> {
const res = await makeRequest<RemoteBundle>({
headers: {
...prepareTokenHeaders(options.sessionToken),
source: options.source,
...(options.requestId && { 'snyk-request-id': options.requestId }),
...(options.org && { 'snyk-org-name': options.org }),
...commonHttpHeaders(options),
},
url: `${options.baseURL}/bundle/${options.bundleHash}`,
method: 'get',
Expand Down Expand Up @@ -302,11 +300,9 @@ export async function extendBundle(
const payloadBody = await compressAndEncode(pick(options, ['files', 'removedFiles']));
const res = await makeRequest<RemoteBundle>({
headers: {
...prepareTokenHeaders(options.sessionToken),
source: options.source,
...(options.requestId && { 'snyk-request-id': options.requestId }),
...{ 'content-type': 'application/octet-stream', 'content-encoding': 'gzip' },
...(options.org && { 'snyk-org-name': options.org }),
'content-type': 'application/octet-stream',
'content-encoding': 'gzip',
...commonHttpHeaders(options),
},
url: `${options.baseURL}/bundle/${options.bundleHash}`,
method: 'put',
Expand Down Expand Up @@ -363,10 +359,7 @@ export async function getAnalysis(
): Promise<Result<GetAnalysisResponseDto, GetAnalysisErrorCodes>> {
const config: Payload = {
headers: {
...prepareTokenHeaders(options.sessionToken),
source: options.source,
...(options.requestId && { 'snyk-request-id': options.requestId }),
...(options.org && { 'snyk-org-name': options.org }),
...commonHttpHeaders(options),
},
url: `${options.baseURL}/analysis`,
method: 'post',
Expand Down Expand Up @@ -404,10 +397,7 @@ export async function initReport(
): Promise<Result<InitUploadResponseDto, GetAnalysisErrorCodes>> {
const config: Payload = {
headers: {
...prepareTokenHeaders(options.sessionToken),
source: options.source,
...(options.requestId && { 'snyk-request-id': options.requestId }),
...(options.org && { 'snyk-org-name': options.org }),
...commonHttpHeaders(options),
},
url: `${options.baseURL}/report`,
method: 'post',
Expand Down Expand Up @@ -435,10 +425,7 @@ export async function getReport(
): Promise<Result<UploadReportResponseDto, GetAnalysisErrorCodes>> {
const config: Payload = {
headers: {
...prepareTokenHeaders(options.sessionToken),
source: options.source,
...(options.requestId && { 'snyk-request-id': options.requestId }),
...(options.org && { 'snyk-org-name': options.org }),
...commonHttpHeaders(options),
},
url: `${options.baseURL}/report/${options.reportId}`,
method: 'get',
Expand Down
18 changes: 9 additions & 9 deletions src/interfaces/analysis-options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,7 @@ export interface AnalysisContext {
};
}

export interface FileAnalysisOptions extends AnalysisContext {
connection: ConnectionOptions;
analysisOptions: AnalysisOptions;
fileOptions: AnalyzeFoldersOptions;
reportOptions?: ReportOptions;
languages?: string[];
}

export interface AnalyzeFoldersOptions extends AnalysisContext {
export interface AnalyzeFoldersOptions {
paths: string[];
symlinksEnabled?: boolean;
defaultFileIgnores?: string[];
Expand All @@ -65,3 +57,11 @@ export interface ReportOptions {
projectName?: string;
targetRef?: string;
}

export interface FileAnalysisOptions extends AnalysisContext {
connection: ConnectionOptions;
analysisOptions: AnalysisOptions;
fileOptions: AnalyzeFoldersOptions;
reportOptions?: ReportOptions;
languages?: string[];
}
50 changes: 35 additions & 15 deletions tests/analysis.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import jsonschema from 'jsonschema';

import { analyzeFolders, extendAnalysis } from '../src/analysis';
import { analyzeFolders, extendAnalysis, analyzeBundle } from '../src/analysis';
import { uploadRemoteBundle } from '../src/bundles';
import { baseURL, sessionToken, source, TEST_TIMEOUT } from './constants/base';
import { sampleProjectPath, bundleFilesFull, bundleExtender } from './constants/sample';
Expand Down Expand Up @@ -301,30 +301,50 @@ describe('Functional test of analysis', () => {
analysisContext: {
flow: 'test',
initiator: 'CLI',
orgDisplayName: 'org',
orgPublicId: 'id',
projectName: 'proj',
projectPublicId: 'id',
org: {
name: 'org',
displayName: 'organization',
publicId: 'id',
flags: {},
},
project: {
name: 'proj',
publicId: 'id',
type: 'code',
},
},
};

const makeRequestSpy = jest.spyOn(needle, 'makeRequest');

await analyzeFolders({
connection: { baseURL, sessionToken, source },
analysisOptions: {
try {
await analyzeBundle({
baseURL,
sessionToken,
source,
org: 'org',
severity: 1,
},
fileOptions: {
paths: [sampleProjectPath],
symlinksEnabled: false,
},
...analysisContext,
});
bundleHash: 'hash',
shard: sampleProjectPath,
...analysisContext,
});
} catch (err) {
// Authentication mechanism should deny the request as this user does not belong to the org 'org'
expect(err).toEqual({
apiName: 'getAnalysis',
statusCode: 401,
statusText: 'Missing, revoked or inactive token',
});
}

const makeRequestSpyLastCalledWith = makeRequestSpy.mock.calls[makeRequestSpy.mock.calls.length - 1][0];
expect(makeRequestSpyLastCalledWith).toEqual(
expect.objectContaining({
body: expect.objectContaining(analysisContext),
headers: expect.objectContaining({
'snyk-org-name': 'org',
source: 'test-source',
}),
}),
);
});
Expand Down
33 changes: 33 additions & 0 deletions tests/bundle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from 'path';

import * as needle from '../src/needle';
import { createBundleFromFolders } from '../src/bundles';
import { baseURL, sessionToken, source } from './constants/base';
import { sampleProjectPath } from './constants/sample';
Expand All @@ -23,4 +24,36 @@ describe('Functional test for bundle creation', () => {
expect(result).toHaveProperty('bundleHash');
expect(result).toHaveProperty('missingFiles');
});

it('sends analysis metadata for bundle request', async () => {
const makeRequestSpy = jest.spyOn(needle, 'makeRequest');

try {
await createBundleFromFolders({
baseURL,
sessionToken,
source,
org: 'org',
paths: [sampleProjectPath],
symlinksEnabled: false,
});
} catch (err) {
// Authentication mechanism should deny the request as this user does not belong to the org 'org'
expect(err).toEqual({
apiName: 'createBundle',
statusCode: 401,
statusText: 'Missing, revoked or inactive token',
});
}

const makeRequestSpyLastCalledWith = makeRequestSpy.mock.calls[makeRequestSpy.mock.calls.length - 1][0];
expect(makeRequestSpyLastCalledWith).toEqual(
expect.objectContaining({
headers: expect.objectContaining({
'snyk-org-name': 'org',
source: 'test-source',
}),
}),
);
});
});

0 comments on commit bf87e11

Please sign in to comment.