Skip to content

Add Step-up rechallenge implementation#2869

Open
rinatkhaziev wants to merge 17 commits into
trunkfrom
feat/rechallenge-v2-defensive-mode
Open

Add Step-up rechallenge implementation#2869
rinatkhaziev wants to merge 17 commits into
trunkfrom
feat/rechallenge-v2-defensive-mode

Conversation

@rinatkhaziev
Copy link
Copy Markdown
Contributor

Description

This pull request adds a comprehensive suite of unit tests for the new "rechallenge" (elevated permissions) flow and related features. The tests cover the rechallenge client, flow orchestration, Apollo GraphQL link integration, defensive mode API, and logout logic, ensuring that the elevated permissions workflow is robust, correctly integrated, and well-covered by automated tests.

Rechallenge/Elevated Permissions Flow Testing:

  • Adds unit tests for the rechallenge client covering session creation, status polling, and token exchange, including error handling for non-2xx responses (__tests__/lib/rechallenge/client.test.ts).
  • Implements tests for the rechallenge flow orchestration, including polling, abort handling, caching, telemetry, and interactive context detection (__tests__/lib/rechallenge/flow.test.ts).
  • Introduces tests for the Apollo rechallenge link, verifying correct header attachment, token caching, retry logic on elevated-permission-required errors, and error propagation (__tests__/lib/rechallenge/link.test.ts).

Defensive Mode API Testing:

  • Adds tests for updateDefensiveModeStatus and updateDefensiveModeConfig API calls, checking input formatting and omission of optional fields (__tests__/lib/defensive-mode/api.test.ts).

Logout Flow Testing:

  • Adds a test to verify that logout purges the primary token, clears the elevated token cache, and emits a telemetry event (__tests__/lib/logout.test.ts).

Changelog Description

Added

Removed

Fixed

Changed

Pull request checklist

New release checklist

Steps to Test

Outline the steps to test and verify the PR here.

Example:

  1. Check out PR.
  2. Run npm run build
  3. Run ./dist/bin/vip-cookies.js nom
  4. Verify cookies are delicious.

rinatkhaziev and others added 16 commits June 4, 2026 14:00
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also extracts API_HOST/API_URL/PRODUCTION_API_HOST into a leaf constants
module and lazy-requires the rechallenge link inside API() to break a
circular-dependency cycle that caused Jest mocks to misfire in the
rechallenge test suite.
Implements `vip defensive-mode configure` with full flag validation,
interactive prompting for missing required flags, and non-interactive
hard-error mode.
…e guards, telemetry order, teardown race)

- configure: log current effective config and proposed input before mutating (Fix 1)
- enable/disable: add --non-interactive option and guard; error on production mutation attempted non-interactively without --skip-confirmation (Fix 2)
- flow: add clientType=cli to rechallenge_required event (Fix 3)
- flow: fire rechallenge_verified before rechallenge_exchanged to match spec order (Fix 4)
- link: split innerSub into firstSub/retrySub to eliminate teardown race during async gap (Fix 5)
- enable/disable/configure: use console.error for error-path chalk.red messages (Fix 6)
- token-cache: document single-blob keychain strategy (Fix 7)
- tests: assert proposed config logged in configure; add non-interactive-production exit tests for enable/disable; assert rechallenge_verified fires before rechallenge_exchanged

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new “step-up / rechallenge” elevated-permissions flow that integrates with the existing Apollo GraphQL client (via a custom ApolloLink), adds an elevated-token cache, and wires the flow into logout. It also adds a new vip defensive-mode CLI command group backed by new defensive-mode GraphQL mutations, along with a broad suite of unit tests around these behaviors.

Changes:

  • Add rechallenge (step-up) client, flow orchestration, ApolloLink integration, error types, and elevated-token keychain cache.
  • Add defensive-mode GraphQL mutation helpers and new CLI commands (vip defensive-mode enable|disable|configure).
  • Add unit tests for rechallenge components, defensive-mode API, logout behavior, and defensive-mode command behavior.

Reviewed changes

Copilot reviewed 22 out of 30 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/lib/token.ts Switches API host/constants import to avoid pulling full api.ts graph.
src/lib/rechallenge/types.ts Defines rechallenge protocol/types and constants.
src/lib/rechallenge/token-cache.ts Implements keychain-backed elevated-token cache keyed by scope.
src/lib/rechallenge/open-browser.ts Adds wrapper around ESM-only open for browser launching.
src/lib/rechallenge/link.ts Adds ApolloLink that pre-attaches cached elevated token and runs rechallenge on elevated-permission errors.
src/lib/rechallenge/index.ts Exposes rechallenge module exports.
src/lib/rechallenge/flow.ts Implements rechallenge orchestration (session create → poll → exchange → cache).
src/lib/rechallenge/errors.ts Adds typed rechallenge error classes.
src/lib/rechallenge/client.ts Adds HTTP client for rechallenge session/status/exchange endpoints.
src/lib/logout.ts Clears elevated-token cache on logout in addition to primary token purge.
src/lib/defensive-mode/api.ts Adds GraphQL mutations/helpers to update defensive-mode status/config.
src/lib/api/http.ts Switches API_HOST import to new constants module (reduces circular deps).
src/lib/api/feature-flags.ts Lazy-initializes Apollo client to break a circular dependency chain.
src/lib/api/constants.ts Introduces shared API host/URL constants (re-exported by api.ts).
src/lib/api.ts Re-exports constants and injects rechallenge link via lazy require() to avoid Jest mock timing issues.
src/bin/vip.js Registers the new defensive-mode top-level CLI command.
src/bin/vip-defensive-mode.js Adds vip defensive-mode parent command and subcommand wiring.
src/bin/vip-defensive-mode-enable.js Adds vip defensive-mode enable command implementation.
src/bin/vip-defensive-mode-disable.js Adds vip defensive-mode disable command implementation.
src/bin/vip-defensive-mode-configure.js Adds vip defensive-mode configure command implementation with flag validation/prompting.
package.json Adds new vip-defensive-mode* bin entries for distribution.
tests/lib/rechallenge/token-cache.test.ts Unit tests for elevated-token cache behavior and corruption handling.
tests/lib/rechallenge/link.test.ts Unit tests for rechallenge ApolloLink preflight, retry, and error propagation.
tests/lib/rechallenge/flow.test.ts Unit tests for rechallenge flow polling/exchange/caching and interactivity detection.
tests/lib/rechallenge/client.test.ts Unit tests for rechallenge HTTP client request shapes and non-2xx error handling.
tests/lib/logout.test.ts Verifies logout clears both primary token and elevated-token cache + telemetry.
tests/lib/defensive-mode/api.test.ts Verifies defensive-mode mutation input formatting and optional field omission.
tests/bin/vip-defensive-mode-enable.js Tests command registration and enable behavior (including non-interactive production safety).
tests/bin/vip-defensive-mode-disable.js Tests command registration and disable behavior (including non-interactive production safety).
tests/bin/vip-defensive-mode-configure.js Tests configure flag validation, non-interactive behavior, logging, and telemetry.

Comment on lines +87 to +91
return (
result.data as {
updateDefensiveModeStatus: { success: boolean; message: string };
}
).updateDefensiveModeStatus;
Comment on lines +114 to +118
return (
result.data as {
updateDefensiveModeConfig: { success: boolean; message: string };
}
).updateDefensiveModeConfig;
Comment on lines +1 to +20
import type { RechallengeStatus } from './types';

export class RechallengeError extends Error {
public readonly scope: string;
constructor( message: string, scope: string ) {
super( message );
this.name = 'RechallengeError';
this.scope = scope;
}
}

export class RechallengeUnsupportedVersionError extends RechallengeError {
constructor( version: string, scope: string ) {
super(
`Server requested rechallenge version "${ version }" but this CLI only supports v2. Update vip-cli.`,
scope
);
this.name = 'RechallengeUnsupportedVersionError';
}
}
Comment on lines +42 to +49
const ext = ( err.extensions ?? {} ) as Record< string, unknown >;
if ( ext.code !== ELEVATED_PERMISSION_ERROR_CODE ) {
continue;
}
const rechallenge = ext.rechallenge as RechallengeExtension | undefined;
if ( rechallenge && typeof rechallenge.createSessionPath === 'string' ) {
return { rechallenge };
}
Comment on lines +1 to +6
import { describe, expect, it, jest, beforeEach } from '@jest/globals';

import http from '../../../src/lib/api/http';
import * as client from '../../../src/lib/rechallenge/client';
import { RechallengeHttpError } from '../../../src/lib/rechallenge/errors';

…ad validation, dedupe commands)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 4, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants