Skip to content

Conversation

@bs-shobhitkumar
Copy link
Contributor

@bs-shobhitkumar bs-shobhitkumar commented Jan 13, 2026

This pull request introduces a new auto domain allow-listing feature to the Percy client and core, enabling automatic validation and management of external domains accessed during snapshot capture. This helps streamline asset handling by validating domains against project configuration and an external service, and by persisting new discoveries for future builds. The implementation includes changes to both the core logic and the client API, as well as comprehensive tests for the new functionality.

The most important changes are:

Core logic for auto domain allow-listing:

  • Added a domain validation state to the Percy class, including sets for pre-approved, pre-blocked, session-allowed, and session-blocked domains, as well as statistics tracking. (packages/core/src/percy.js)
  • Integrated domain validation checks into the network layer, including logic to check project configuration, session cache, and an external validation service, with fail-open behavior on errors. (packages/core/src/network.js) [1] [2]
  • Updated resource handling to use domain validation results for both blocking and capturing resources. (packages/core/src/network.js) [1] [2]

Project domain configuration persistence:

  • Implemented methods in the Percy class to load project domain config at startup and save newly discovered allowed/blocked domains at shutdown, integrating with the Percy client API. (packages/core/src/percy.js) [1] [2] [3]

Percy client API enhancements:

  • Added a generic patch method and new methods updateProjectDomainConfig and validateDomain to the PercyClient class to support updating project domain configuration and validating domains via an external service. (packages/client/src/client.js) [1] [2]

Test coverage for new features:

  • Added comprehensive tests for updateProjectDomainConfig and validateDomain methods, including positive and negative scenarios and request payload validation. (packages/client/test/client.test.js, packages/client/test/helpers.js) [1] [2]

Wiring and context propagation:

  • Passed the domain validation context and client through the discovery and network layers to ensure the new logic is available where needed. (packages/core/src/discovery.js, packages/core/src/network.js) [1] [2]


// Validates a domain with the Cloudflare worker endpoint
async validateDomain(hostname, options = {}) {
const endpoint = 'https://winter-morning-fa32.shobhit-k.workers.dev/validate-domain';
Copy link
Contributor

Choose a reason for hiding this comment

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

It should come from API maybe as response of project fetch or build fetch, we don't want CLI release in case we change it or if we move to alternative

const ABORTED_MESSAGE = 'Request was aborted by browser';

// Domain validation constants
const DOMAIN_VALIDATION_ENDPOINT = 'https://winter-morning-fa32.shobhit-k.workers.dev/validate-domain';
Copy link
Contributor

Choose a reason for hiding this comment

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

should not be hardcoded

// Check if validation is already pending for this domain
if (pending.has(hostname)) {
network.log.debug(`Domain validation: Waiting for pending validation of ${hostname}`, network.meta);
return pending.get(hostname);
Copy link
Contributor

Choose a reason for hiding this comment

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

If pending what's the guarantee it will be set by the time it is fetched?

// Extract hostname for domain validation
let hostname;
try {
hostname = new URL(url).hostname;
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of hostname use host to handle domain with port

Comment on lines +679 to +684
let hostname;
try {
hostname = new URL(url).hostname;
} catch (e) {
hostname = null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

make a method for it

Comment on lines +679 to +684
let hostname;
try {
hostname = new URL(url).hostname;
} catch (e) {
hostname = null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

make a method for it


// Load domain config early if domain validation is enabled
// This ensures pre-approved domains are loaded before discovery starts
if (!this.skipUploads) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should keep some kill switch via ENV variable to stop this flow completely in case something goes wrong user will have some way to stop this flow

network.log.debug(`Domain validation: ${hostname} validated as ALLOWED`, network.meta);
return 'allowed';
} else {
sessionBlocked.add(hostname);
Copy link
Contributor

Choose a reason for hiding this comment

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

this can be risky if some domain took time to load, it will end up adding it in blocked which should not be ideal case as in future all builds will go as disallowedHostname.

preApproved: new Set(), // Domains from project config
preBlocked: new Set(), // Domains from project config
sessionAllowed: new Set(), // Newly discovered allowed domains this session
sessionBlocked: new Set(), // Newly discovered blocked domains this session
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason for blocked domains as it can have high impact, allowing is still fine as it can increase our cost but disallow can have negative impact, we can store on our side for reference but should not use this in CLI imo

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.

3 participants