Skip to content

fix: respect command ignores HTTP_PROXY#2805

Open
harshit078 wants to merge 7 commits into
Redocly:mainfrom
harshit078:fix-respect-HTTP-PROXY
Open

fix: respect command ignores HTTP_PROXY#2805
harshit078 wants to merge 7 commits into
Redocly:mainfrom
harshit078:fix-respect-HTTP-PROXY

Conversation

@harshit078
Copy link
Copy Markdown
Contributor

@harshit078 harshit078 commented May 11, 2026

What/Why/How?

  • using withConnectionClient () function in index.ts as a BaseResolver which inreturn should fetch HTTP_PROXY and other related.
  • Fixed the respect command so that loading remote sourceDescriptions and external $refs honors HTTP_PROXY / HTTPS_PROXY / NO_PROXY

Reference

#2668

Testing

Screenshots (optional)

Check yourself

  • This PR follows the contributing guide
  • All new/updated code is covered by tests
  • Core code changed? - Tested with other Redocly products (internal contributions only)
  • New package installed? - Tested in different environments (browser/node)
  • Documentation update has been considered

Security

  • The security impact of the change has been considered
  • Code follows company security practices and guidelines

Note

Medium Risk
Changes how redocly respect performs HTTP fetches by wiring proxy-aware fetching into external $ref resolution; misconfiguration could affect network access in proxied environments. Scope is limited to fetch wiring and adds targeted tests.

Overview
Fixes redocly respect to honor HTTP_PROXY, HTTPS_PROXY, and NO_PROXY not just for loading remote source descriptions but also when resolving external $refs, by providing a proxy-aware BaseResolver (externalRefResolver) configured with withConnectionClient().

Extends tests to assert withConnectionClient() returns the bare Undici fetch when no proxy/certs are set, and a wrapped fetch when proxy env vars are present, and adds a changeset for a patch release.

Reviewed by Cursor Bugbot for commit 04e1fb7. Bugbot is set up for automated code reviews on this repo. Configure here.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 11, 2026

🦋 Changeset detected

Latest commit: 04e1fb7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@redocly/cli Patch
@redocly/openapi-core Patch
@redocly/respect-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@harshit078 harshit078 marked this pull request as ready for review May 13, 2026 08:22
@harshit078 harshit078 requested review from a team as code owners May 13, 2026 08:22
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a19b545. Configure here.

Comment thread packages/cli/src/commands/respect/connection-client.ts Outdated
"@redocly/cli": patch
---

Fixed issue wherein `redocly respect` did not honor `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment variables when loading remote source descriptions or external `$ref`s. This extends the same behavior to ref resolution.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
Fixed issue wherein `redocly respect` did not honor `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment variables when loading remote source descriptions or external `$ref`s. This extends the same behavior to ref resolution.
Fixed an issue where the Respect command did not honor the `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment variables when loading remote source descriptions or resolving external `$ref`s. Proxy settings are now consistently applied during reference resolution as well.

const externalRefResolver = new BaseResolver({
http: {
headers: config.resolve?.http?.headers ?? [],
customFetch: withConnectionClient(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
customFetch: withConnectionClient(),
customFetch: withConnectionClient(mtlsCerts),

});
});

describe('withConnectionClient (proxy-only behavior)', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
describe('withConnectionClient (proxy-only behavior)', () => {
describe('withConnectionClient (proxy-only behavior)', () => {
const PROXY_ENV_KEYS = [
'HTTPS_PROXY',
'HTTP_PROXY',
'https_proxy',
'http_proxy',
'NO_PROXY',
'no_proxy',
] as const;

const savedEnv: Record<string, string | undefined> = {};

beforeEach(() => {
savedEnv.HTTPS_PROXY = process.env.HTTPS_PROXY;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we use smth like this to save/delete envs

    for (const key of PROXY_ENV_KEYS) {
      savedEnv[key] = process.env[key];
      delete process.env[key];
    }

});
});

describe('withConnectionClient (proxy-only behavior)', () => {
Copy link
Copy Markdown
Contributor

@DmitryAnansky DmitryAnansky May 15, 2026

Choose a reason for hiding this comment

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

Maybe it will make sense to move this check into packages/cli/src/__tests__/commands/respect/respect.test.ts level and also test mTLS

Smth like this, or similar:

describe('handleRespect externalRefResolver wiring', () => {
  const PROXY_ENV_KEYS = [
    'HTTPS_PROXY',
    'HTTP_PROXY',
    'https_proxy',
    'http_proxy',
    'NO_PROXY',
    'no_proxy',
  ] as const;
  const savedEnv: Record<string, string | undefined> = {};

  const PEM_CERT =
    '-----BEGIN CERTIFICATE-----\nY2VydA==\n-----END CERTIFICATE-----';
  const PEM_KEY = '-----BEGIN PRIVATE KEY-----\na2V5\n-----END PRIVATE KEY-----';

  beforeEach(() => {
    vi.clearAllMocks();
    for (const key of PROXY_ENV_KEYS) {
      savedEnv[key] = process.env[key];
      delete process.env[key];
    }
    vi.mocked(run).mockResolvedValue([
      {
        hasProblems: false,
        hasWarnings: false,
        file: 'test.arazzo.yaml',
        executedWorkflows: [],
        options: {} as any,
        ctx: {} as any,
        totalTimeMs: 0,
        totalRequests: 0,
        globalTimeoutError: false,
        secretValues: [],
      },
    ]);
  });

  afterEach(() => {
    for (const key of PROXY_ENV_KEYS) {
      const value = savedEnv[key];
      if (value !== undefined) {
        process.env[key] = value;
      } else {
        delete process.env[key];
      }
    }
  });

  async function invokeHandleRespect(argvOverrides: Partial<RespectArgv> = {}) {
    const config = await openapiCore.createConfig({});
    await handleRespect({
      argv: {
        files: ['test.arazzo.yaml'],
        'max-steps': 2000,
        'max-fetch-timeout': 40_000,
        'execution-timeout': 3_600_000,
        'no-secrets-masking': false,
        ...argvOverrides,
      } as RespectArgv,
      config,
      version: '1.0.0',
      collectSpecData: vi.fn(),
    });
    const callArgs = vi.mocked(run).mock.calls[0]?.[0];
    return callArgs;
  }

  function getResolverCustomFetch(resolver: BaseResolver | undefined) {
    return (resolver as unknown as { config: { http: { customFetch?: unknown } } } | undefined)
      ?.config.http.customFetch;
  }

  it('should pass an externalRefResolver instance to run', async () => {
    const callArgs = await invokeHandleRespect();
    expect(callArgs?.externalRefResolver).toBeInstanceOf(BaseResolver);
  });

  it('should use the bare undici fetch when no proxy and no mTLS are configured', async () => {
    const callArgs = await invokeHandleRespect();
    expect(getResolverCustomFetch(callArgs?.externalRefResolver)).toBe(undiciFetch);
  });

  it('should use a proxy-aware customFetch when HTTPS_PROXY is set', async () => {
    process.env.HTTPS_PROXY = 'http://proxy.local:8080';
    const callArgs = await invokeHandleRespect();
    const customFetch = getResolverCustomFetch(callArgs?.externalRefResolver);
    expect(customFetch).not.toBe(undiciFetch);
    expect(typeof customFetch).toBe('function');
  });

  it('should use a proxy-aware customFetch when HTTP_PROXY is set', async () => {
    process.env.HTTP_PROXY = 'http://proxy.local:8080';
    const callArgs = await invokeHandleRespect();
    const customFetch = getResolverCustomFetch(callArgs?.externalRefResolver);
    expect(customFetch).not.toBe(undiciFetch);
    expect(typeof customFetch).toBe('function');
  });

  it('should use an mTLS-aware customFetch when argv.mtls is provided', async () => {
    const callArgs = await invokeHandleRespect({
      mtls: {
        'https://internal-api.example.com': {
          clientCert: PEM_CERT,
          clientKey: PEM_KEY,
        },
      },
    });
    const customFetch = getResolverCustomFetch(callArgs?.externalRefResolver);
    expect(customFetch).not.toBe(undiciFetch);
    expect(typeof customFetch).toBe('function');
  });
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@harshit078 what do you think ?

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