Skip to content
Merged
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
2 changes: 0 additions & 2 deletions .envrc.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ export GRAPHQL_PATH='/graphql';
export EOL_REPORT_URL='https://eol-report-card.apps.herodevs.com/reports';
export ANALYTICS_URL='https://eol-api.herodevs.com/track';

# Authentication (set to 'true' to enable auth requirement for scans)
export ENABLE_AUTH='false';
export OAUTH_CONNECT_URL='';
export OAUTH_CLIENT_ID='';

Expand Down
28 changes: 28 additions & 0 deletions e2e/setup/mock-auth-hooks.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* ESM loader hooks that replace auth.svc.ts with a mock during E2E tests.
* This avoids hitting the system keyring (unavailable in CI).
*/
export async function load(url, context, nextLoad) {
if (url.endsWith('/service/auth.svc.ts') || url.endsWith('/service/auth.svc.js')) {
return {
format: 'module',
shortCircuit: true,
source: `
export class AuthError extends Error {
constructor(message, code) {
super(message);
this.name = 'AuthError';
this.code = code;
}
}
export function persistTokenResponse() { return Promise.resolve(); }
export function getAccessToken() { return Promise.resolve('test-token'); }
export function requireAccessToken() { return Promise.resolve('test-token'); }
export function logoutLocally() { return Promise.resolve(); }
export function requireAccessTokenForScan() { return Promise.resolve('test-token'); }
`,
};
}

return nextLoad(url, context);
}
3 changes: 3 additions & 0 deletions e2e/setup/register-mock-auth.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { register } from 'node:module';

register('./mock-auth-hooks.mjs', import.meta.url);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"readme": "npm run ci:fix && npm run build && oclif readme && sed -i '' 's|/plugin-help/blob/v|/plugin-help/blob/|; s|/plugin-update/blob/v|/plugin-update/blob/|' README.md",
"test": "vitest run",
"test:watch": "vitest watch",
"test:e2e": "globstar -- node --import tsx --test \"e2e/**/*.test.ts\"",
"test:e2e": "globstar -- node --import tsx --import ./e2e/setup/register-mock-auth.mjs --test \"e2e/**/*.test.ts\"",
"typecheck": "tsc --noEmit",
"version": "oclif manifest",
"postversion": "node scripts/update-install-script-version.js && git add README.md"
Expand Down
6 changes: 2 additions & 4 deletions src/api/nes.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ const createAuthorizedFetch =
async (input, init) => {
const headers = new Headers(init?.headers);

if (config.enableAuth) {
const token = await tokenProvider();
headers.set('Authorization', `Bearer ${token}`);
}
const token = await tokenProvider();
headers.set('Authorization', `Bearer ${token}`);

return fetch(input, { ...init, headers });
};
Expand Down
4 changes: 0 additions & 4 deletions src/commands/auth/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { createInterface } from 'node:readline';
import { URL } from 'node:url';
import { Command } from '@oclif/core';
import { ensureUserSetup } from '../../api/user-setup.client.ts';
import { config } from '../../config/constants.ts';
import { persistTokenResponse } from '../../service/auth.svc.ts';
import { getClientId, getRealmUrl } from '../../service/auth-config.svc.ts';
import { getErrorMessage } from '../../service/log.svc.ts';
Expand Down Expand Up @@ -48,9 +47,6 @@ export default class AuthLogin extends Command {
return;
}

if (!config.enableUserSetup) {
return;
}
try {
await ensureUserSetup();
} catch (error) {
Expand Down
4 changes: 1 addition & 3 deletions src/commands/scan/eol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ export default class ScanEol extends Command {
public async run(): Promise<EolReport | undefined> {
const { flags } = await this.parse(ScanEol);

if (config.enableAuth) {
await requireAccessTokenForScan();
}
await requireAccessTokenForScan();

track('CLI EOL Scan Started', (context) => ({
command: context.command,
Expand Down
11 changes: 0 additions & 11 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,6 @@ export const GIT_OUTPUT_FORMAT = `"${['%h', '%an', '%ad'].join('|')}"`;
export const DEFAULT_DATE_FORMAT = 'yyyy-MM-dd';
export const DEFAULT_DATE_COMMIT_FORMAT = 'MM/dd/yyyy, h:mm:ss a';
export const DEFAULT_DATE_COMMIT_MONTH_FORMAT = 'MMMM yyyy';
export const ENABLE_AUTH = false;
export const ENABLE_USER_SETUP = false;

const toBoolean = (value: string | undefined): boolean | undefined => {
if (value === 'true') return true;
if (value === 'false') return false;
return undefined;
};

// Trackers - Constants
export const DEFAULT_TRACKER_RUN_DATA_FILE = 'data.json';
export const TRACKER_GIT_OUTPUT_FORMAT = `"${['%H', '%an', '%ad'].join('|')}"`;
Expand All @@ -40,8 +31,6 @@ export const config = {
graphqlHost: process.env.GRAPHQL_HOST || GRAPHQL_HOST,
graphqlPath: process.env.GRAPHQL_PATH || GRAPHQL_PATH,
analyticsUrl: process.env.ANALYTICS_URL || ANALYTICS_URL,
enableAuth: toBoolean(process.env.ENABLE_AUTH) ?? ENABLE_AUTH,
enableUserSetup: toBoolean(process.env.ENABLE_USER_SETUP) ?? ENABLE_USER_SETUP,
concurrentPageRequests,
pageSize,
};
Expand Down
5 changes: 5 additions & 0 deletions test/api/nes.client.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { CreateEolReportInput } from '@herodevs/eol-shared';
import { vi } from 'vitest';
import { submitScan } from '../../src/api/nes.client.ts';
import { SCAN_ORIGIN_AUTOMATED, SCAN_ORIGIN_CLI } from '../../src/config/constants.ts';
import { FetchMock } from '../utils/mocks/fetch.mock.ts';

vi.mock('../../src/service/auth.svc.ts', () => ({
requireAccessTokenForScan: vi.fn().mockResolvedValue('test-token'),
}));

function getGraphQLVariables(fetchMock: FetchMock, callIndex = 0): Record<string, unknown> {
const calls = fetchMock.getCalls();
const init = calls[callIndex]?.init;
Expand Down
6 changes: 6 additions & 0 deletions test/api/user-setup.client.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { vi } from 'vitest';
import { ApiError } from '../../src/api/errors.ts';
import { completeUserSetup, ensureUserSetup, getUserSetupStatus } from '../../src/api/user-setup.client.ts';
import { FetchMock } from '../utils/mocks/fetch.mock.ts';

vi.mock('../../src/service/auth.svc.ts', () => ({
requireAccessTokenForScan: vi.fn().mockResolvedValue('test-token'),
requireAccessToken: vi.fn().mockResolvedValue('test-token'),
}));

describe('user-setup.client', () => {
let fetchMock: FetchMock;

Expand Down
17 changes: 1 addition & 16 deletions test/commands/auth/login.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,6 @@ vi.mock('http', () => ({
},
}));

vi.mock('../../../src/config/constants.ts', () => ({
__esModule: true,
config: {
get enableAuth() {
return process.env.ENABLE_AUTH === 'true';
},
get enableUserSetup() {
return process.env.ENABLE_USER_SETUP === 'true';
},
},
}));

vi.mock('../../../src/api/user-setup.client.ts', () => ({
__esModule: true,
ensureUserSetup: vi.fn(),
Expand Down Expand Up @@ -148,13 +136,11 @@ describe('AuthLogin', () => {
closeMock.mockClear();
openMock.mockResolvedValue(undefined);
ensureUserSetupMock.mockResolvedValue(undefined);
delete process.env.ENABLE_USER_SETUP;
});

afterEach(() => {
vi.clearAllMocks();
delete process.env.OAUTH_CALLBACK_PORT;
delete process.env.ENABLE_USER_SETUP;
serverInstances.length = 0;
persistTokenResponseMock.mockClear();
});
Expand Down Expand Up @@ -387,10 +373,10 @@ describe('AuthLogin', () => {
await command.run();

expect(persistTokenResponseMock).toHaveBeenCalledWith(tokenResponse);
expect(ensureUserSetupMock).toHaveBeenCalledTimes(1);
});

it('runs user setup after login', async () => {
process.env.ENABLE_USER_SETUP = 'true';
const command = createCommand(6001);
const tokenResponse = { access_token: 'access', refresh_token: 'refresh' };
const commandWithInternals = command as unknown as {
Expand All @@ -406,7 +392,6 @@ describe('AuthLogin', () => {
});

it('fails login when user setup fails', async () => {
process.env.ENABLE_USER_SETUP = 'true';
ensureUserSetupMock.mockRejectedValueOnce(new Error('setup failed'));
const command = createCommand(6002);
const tokenResponse = { access_token: 'access', refresh_token: 'refresh' };
Expand Down